getpeername()不会返回正确的端口,但会返回远程主机套接字语言C的正确地址

时间:2014-04-12 17:36:43

标签: c sockets tcp p2p

我想问一下getpeername()函数,因为它返回数据作为标题状态。我试图直接从accept()函数获取值,结果也是一样的。即使地址的值是正确的,端口的值似乎也是随机出现的(地址是127.0.0.1,因为我在一台机器上运行多进程)。 getpeername()的返回码为0(status = 0)。我正在使用gcc版本4.8.1。我写了一个没有服务器的对等2对等聊天应用程序以下是我的代码:

struct sockaddr_in addr;
socklen_t addr_len;
int tempPort, serverSockfd;
char test[100];

// Get serverSockfd successfully....
serverSockFd = initializeSock(PORT) // In this function I initialize socket(), bind() and listen(), serverSockFd is returned by the value of socket() 


addr_len = sizeof addr;
newSock = accept(serverSockfd, (struct sockaddr *)&addr, &addr_len);
tempPort = ntohs(addr.sin_port);
inet_ntop(AF_INET, &(addr.sin_addr), test, sizeof test);

printf("tempPort\t%d\n", tempPort);
printf("test\t%s\n", test);

addr_len = sizeof addr; 
if ((status = getpeername(newSock, (struct sockaddr *) &addr, &addr_len)) != 0){  
  printf("getpeername() error!\n");
}

tempPort = ntohs(addr.sin_port);
inet_ntop(AF_INET, &(addr.sin_addr), test, sizeof test);

printf("tempPort\t%d\n", tempPort);
printf("test\t%s\n", test);    

非常感谢您的评论。这是initializeSock()中的部分代码:

sd = socket(AF_INET, SOCK_STREAM, 0);

if(sd < 0)
{
  perror("SocketInit(): socket() error!\n");
  exit(1);
}

ret_val = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char*) &flag, sizeof(flag));
if(ret_val == -1)
{
  perror("SocketInit(): setsockopt(SO_REUSEADDR) error!\n");
  exit(1);
}


gethostname(hostname,100);
host_entry = gethostbyname(hostname);
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list));

ret_val = bind(sd, (struct sockaddr*) &addr, sizeof(addr));

if(ret_val == -1)
{
  perror("SocketInit(): bind() error!\n");
  printf("For port:%d\n",port);
  exit(1);
}
....
return sd;

这是连接到对等方的服务器部分的代码。 ConnectSock(portOfPeerA):

sd = socket(AF_INET, SOCK_STREAM, 0);  

if(sd < 0)
{
  perror("ConnectToServer(): socket() error!\n");
  exit(1);
}

if (port != 0) {

addr.sin_family = AF_INET;
addr.sin_port = htons(portOfPeerA);
addr.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list));

// Do I need to bind() the port of peer B when it would like to connect to peer A? 

ret_val = connect(sd, (struct sockaddr*)&addr, sizeof(addr)); 
if(ret_val == -1)
{
  printf("Error connect());
  exit(1);
}
...

2 个答案:

答案 0 :(得分:1)

我不知道你从对等端接受哪个端口,但如果对等端连接到你的服务器(例如一个呼叫接受),它将从(或多或少)随机端口连接,这就是TCP的工作方式。只有在连接之前对等体明确绑定到该端口时,它才从固定端口连接。

这意味着,对等体发起端口没有在服务器端(代码片段所在的位置)定义,而是在客户端(调用connect的一侧以及只进行连接但没有绑定的位置)。

但是,请注意,如果客户端和服务器都使用固定的IP和端口,它可能会给重复连接带来问题,因为这样你就可以在TCP中获得相同的4-tupel,它定义了重复连接的连接,从而进入各种TIME_WAIT状态的所有麻烦。因此,最好让客户端选择一个可用的端口,而不是强迫它使用特定的端口。

答案 1 :(得分:1)

getpeername()(和accept())报告远程方本地绑定到的IP和端口。如果远程方是在调用bind()之前未调用connect()的客户端,则connect()执行对随机可用端口的隐式绑定。这就是你所看到的,它是典型的用法。 大多数客户端不需要在bind()之前调用connect(),但有些情况需要这样做,所以不要排除它。