C linux x86_64下IPv4套接字的非常快速的ip as int查找?

C linux x86_64下IPv4套接字的非常快速的ip as int查找?,c,linux,sockets,tcp,C,Linux,Sockets,Tcp,linux x86_64,gcc,ipv4 下面是我如何理解找出我的IPv4客户端是谁的。首先,我从一个客户端句柄开始,它不是一个指针,而是一个整数(嗯?)。然后,我需要为目标sockaddr结构分配空间,并为无符号int分配空间以保持其长度(作为引用传递)。然后,我使用整数客户端句柄和我的目标sockaddress和sockaddress长度调用getsockname()。(在内部,可能是getsockname()将内核的IP表示和其他信息复制到我自己的sockaddr中。)然后我需要使用so

linux x86_64,gcc,ipv4

下面是我如何理解找出我的IPv4客户端是谁的。首先,我从一个客户端句柄开始,它不是一个指针,而是一个整数(嗯?)。然后,我需要为目标sockaddr结构分配空间,并为无符号int分配空间以保持其长度(作为引用传递)。然后,我使用整数客户端句柄和我的目标sockaddress和sockaddress长度调用getsockname()。(在内部,可能是getsockname()将内核的IP表示和其他信息复制到我自己的sockaddr中。)然后我需要使用sockaddr结构调用ntoa()以获取字符串。最后,我需要把这个字符串转换成一个整数。(还有getpeername和getsockname。)

这些就是我所看到的例子。这似乎是可移植的,但对于延迟很重要的服务器来说效率很低。但假设我想留在x86_64体系结构和IPv4上的linux内部。我猜内核内部已经在某处将IP号码存储为int,因此这里的大多数往返调用都是不必要的,这样就可以直接查找IPv4,并且在没有中间存储的情况下更快。这样的功能存在吗?我找了很长时间,但没找到

如果getsockname()函数有一个简单地返回IP表示形式为单个整数的替代方法,这将非常有意义。这还可以节省制作副本的时间和开销。这是否存在?(顺便说一句,如果它确实存在,那么使用类似于ntoa()的调用将此唯一的per-IP int映射到标准的xx.xx.xx.xx字符串是合乎逻辑的,也就是说,不需要中间地址。)

如果这样的函数不存在,至少,我应该能够避免ntoa到字符串和返回到整数的转换。这意味着我必须知道sockaddr结构中的哪个字节(甚至是否)代表IP,这样我就可以将这些字节转换成4字节的C整数。我想这是字节2-6。对吧?


/根据法律

我试图分析你的问题-我可能弄错了一些细节

客户端句柄,它不是指针而是整数

  • 事实上,这是一个问题
为目标sockaddr结构分配空间,并为无符号int分配空间以保持其长度

  • 是的,这些确实需要分配,但从哪里分配并不重要。从堆栈中分配肯定比从堆中分配快(malloc()和friends)
“我使用整数客户端句柄和我的目标sockaddress和sockaddress长度调用getsockname()”

我不确定您是在查找给定套接字的本地地址还是远程地址:

  • 我会给你当地的地址
  • 我会给你远程地址
无论如何,如果您只需要IP地址的
int
表示形式,那么我看不出有任何必要进行任何类似ntoa()的调用。get[peer | sock]name()调用填充的
struct sockaddr_in
中已经包含了该名称

因此,假设您已经拥有客户机FD(从
accept()
返回),并且您需要该套接字的远程地址,那么您所需要做的就是这样:

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

...

    struct sockaddr_in peer_sa;                         // Stack allocation
    socklen_t peer_sa_len = sizeof(struct sockaddr_in); // Stack allocation
    int fd;
    int status;

...

    // fd is the client file descriptor, as returned by accept()
    status = getpeername(fd, (struct sockaddr *)&peer_sa, &peer_sa_len);
    // check your return codes!

    printf("peer address %s as int is %d\n",
       inet_ntoa(peer_sa.sin_addr), peer_sa.sin_addr.s_addr);
#包括
#包括
#包括

#include提供地址的文本表示。

由IPv4连接的
getsockname()
getpeername()
填写的
sockaddr\u结构是套接字地址的内部二进制表示形式

如果在*sin
中有一个指向已填写的
sockaddr\u的指针
sin>sin\u addr.s\u addr
是一个
uint32\u t
,以网络字节顺序表示IPv4地址

请注意,
getsockname()
检索连接本地端的地址,
getpeername()
检索远程端的地址。

(警告:我是这方面的初学者。)

好的,我想我现在已经把代码弄清楚了。84行。代码不可移植。只有当服务器是linux x86_64时,它才应该与IPv4一起工作。它应该使用gcc进行编译,并干净地开箱即用地运行

下面启动一个接受单个客户端的TCP服务器。服务器有其整数句柄servSock,客户端有其整数句柄clntSock。该代码包含的函数只接受这些整数句柄作为输入,并以唯一整数形式(例如iwhareyu)或字符串形式(例如swhoareyu)返回服务器和客户端IP地址

我相信这段代码运行良好,包括执行所有适当的清理代码。(它不会超时,但这并不重要,因为它在客户端出现后立即关闭连接。没有recv或send。)有时,它返回0.0.0,有时返回127.0.0.1,但我相信这是正常行为

如果仍然有一个错误,即使是轻微的,请让我知道。在处理网络和许多过程时,由于偏执

#include <stdio.h>      // printf, fprintf
#include <sys/socket.h> // socket, bind, connect
#include <arpa/inet.h>  // sockaddr_in, inet_ntoa
#include <stdlib.h>     // exit
#include <string.h>     // strcpy, bzero
#include <unistd.h>     // close

/****************************************************************/
#define IPNAMELEN 32
typedef char IPNAME[IPNAMELEN];  // must fit 4*4 + terminator

/****************************************************************/

static inline unsigned long iwho( const int clntSocket,
              int (*function)(const int, struct sockaddr *, unsigned int *) ) {
  struct sockaddr_in ipsock_in;
  unsigned int cisl= sizeof(struct sockaddr_in);
  if (getpeername( clntSocket, (struct sockaddr *)&ipsock_in, &cisl )) return 0;
  return  *((unsigned long *) (&ipsock_in.sin_addr));
}

static inline unsigned long iwhoareyou( const int clntSocket ) {
    return iwho(clntSocket, getpeername ); }

static inline char *swhoareyou( const int clntSocket, IPNAME ipbuf ) {
  unsigned long il= iwhoareyou(clntSocket);
  return strcpy(ipbuf, inet_ntoa( *((struct in_addr *) (&il)) ));
}


static inline unsigned long iwhoami( const int servSocket ) {
     return iwho(servSocket, getsockname ); }

static inline char *swhoami( const int servSocket, IPNAME ipbuf ) {
  unsigned long il= iwhoareyou(servSocket);
  return strcpy(ipbuf, inet_ntoa( *((struct in_addr *) (&il)) ));
}


/****************************************************************/
int main() {
  const unsigned short ServPort=8081;

  void die(char *s) { fputs(s, stderr); fputc('\n', stderr); exit(1); }

  int servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (servSock<=0) die("cannot socket()");

  struct sockaddr_in ServAddr;
  bzero( &ServAddr, sizeof(ServAddr));
  ServAddr.sin_family = AF_INET;
  ServAddr.sin_addr.s_addr = htonl(INADDR_ANY);
  ServAddr.sin_port = htons(ServPort);

  {
    int yes=1;    // tell the OS that we want to use it again
    if (setsockopt(servSock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) die("cannot setsockopt");
  }

  if (bind(servSock, (struct sockaddr *) &ServAddr, sizeof(ServAddr)) < 0) die("cannot bind");

  if (listen(servSock, 2) < 0) die("cannot listen");

  struct sockaddr_in ClntAddr;
  unsigned int clntLen = sizeof(ClntAddr);
  int clntSock = accept(servSock, (struct sockaddr *) &ClntAddr, &clntLen);
  if (clntSock < 0) die("cannot accept()");

  printf("Server= %s.\n", inet_ntoa(ServAddr.sin_addr));
  printf("Client= %s.\n", inet_ntoa(ClntAddr.sin_addr));

  IPNAME buf;
  printf("Via Function on clntSock: '%lu' and '%s'\n", iwhoareyou(clntSock), swhoareyou(clntSock, buf));
  printf("Via Function on servSock: '%lu' and '%s'\n", iwhoami(servSock), swhoami(servSock, buf));

  if (close(clntSock)) die("cannot close clnt");
  if (close(servSock)) die("cannot close serv");

  printf("Happy Ending\n");
  return 0;
}
#包括//printf、fprintf
#包括//套接字、绑定、连接
#包括//sockaddr\u in,inet\u ntoa
#包括//退出
#包括//strcpy,bzero
#包括//关闭
/****************************************************************/
#定义IPNAMELEN 32
typedef char IPNAME[IPNAMELEN];//必须安装4*4+端接器
/****************************************************************/
静态内联无符号长iwho(const int clntSocket,
int(*函数)(常量int,结构sockaddr*,无符号int*){
ipsock_中的结构sockaddr_;
unsigned int-cisl=sizeof(结构sockaddr\u-in);
if(getpeername(clntSocket,(struct sockaddr*)和ipsock_in,&cisl))返回0;
返回*((无符号长*)(&ipsock_in.sin_addr));
}
静态内联无符号长iwhareyu(const int clntSocket)