连接到自己(并占用端口号)

时间:2014-12-30 16:00:59

标签: linux networking bind connect

我们遇到一种情况,即应用程序通过系统分配的端口号显然“半连接”并且在Linux上“卡住”(特别是Centos 6.4)。

情况如下:

一个(python)应用程序试图连接到某个服务,假设在IP地址192.168.1.201:8081。由于某种原因,分配的传出端口是8081.连接成功但是套接字上没有进一步的活动,因为它没有真正连接但是有一半中途连接(我的猜测是只有一半的握手完成并且Linux正在进行其余的在后台改善并行性)。套接字上的read语句会挂起,等待连接的其余部分完成。

这是一个复制问题的简单C ++程序。使用您运行的主机的IP地址运行它。这是特殊的,因为我们将连接套接字绑定到一个端口(这是合法的),然后连接到相同的地址和端口,而不会生成错误消息,没有“监听”,并且读取挂起。

  
    

./ foo 192.168.1.201     连接......去读......'

         

ss -na     ESTAB 0 0 192.168.1.201:8081 192.168.1.201:8081

  

如果您终止该程序,套接字将进入Time-Wait:

  
    

TIME-WAIT 0 0 192.168.1.201:8081 192.168.1.201:8081

  

问题是:系统分配的端口是否会发生这种情况?你可以进入一个状态,在那里出站地址/端口最终匹配目标地址/端口和系统死锁?这似乎就是我们所看到的。

谢谢,

- 迈克

程序:

#include <assert.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h> 

int main(int argc, char *argv[])
{
    int ret;
    int sockfd = 0, n = 0;
    char recvBuff[1024];
    struct sockaddr_in serv_addr; 
    struct sockaddr_in sa_loc;

    if(argc != 2)
    {
        printf("\n Usage: %s <ip of server> \n",argv[0]);
        return 1;
    } 

    memset(recvBuff, '0',sizeof(recvBuff));
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        printf("\n Error : Could not create socket \n");
        return 1;
    } 

    memset(&sa_loc, 0, sizeof(struct sockaddr_in));
    sa_loc.sin_family = AF_INET;
    sa_loc.sin_port = htons(8081);
    sa_loc.sin_addr.s_addr = inet_addr(argv[1]);

    ret = bind(sockfd, (struct sockaddr *)&sa_loc, sizeof(struct sockaddr));

    if (ret != 0) {
        perror("bind");
        exit(1);
    }

    memset(&serv_addr, '0', sizeof(serv_addr)); 

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(8081); 

    if(inet_pton(AF_INET, argv[1], &serv_addr.sin_addr)<=0)
    {
        printf("\n inet_pton error occured\n");
        return 1;
    } 

    ret = connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
    if (ret != 0) {
        perror("connect");
        exit(1);
    } 

    printf("Connected...going to read...\n"); fflush(stdout);

    while ( (n = read(sockfd, recvBuff, sizeof(recvBuff)-1)) > 0) {
        recvBuff[n] = 0;
        printf("%s", recvBuff); fflush(stdout);
    } 

    if(n <= 0) {
        perror("read");
        exit(1);
    } 

    return 0;
}

1 个答案:

答案 0 :(得分:0)

通过将套接字绑定到端口然后连接到同一个端口,您建立了一种套接字与其自身的环回连接。

  

系统分配的端口会发生这种情况吗?

不,它不能,因为connect(3)承诺:

  

如果套接字尚未绑定到本地地址,    connect ()将它绑定到一个地址,除非   套接字的地址族是AF_UNIX,是一个未使用的本地地址。

未使用的本地地址与运行服务器的套接字所绑定的地址永远不会相同。此外,如果该端口的服务器已经运行,则客户端中的bind()将不会成功。

  

你能进入一个出境地址/端口以某种方式结束的状态吗?   匹配目标地址/端口和系统死锁?

如果我们以这种方式显式编程,我们只能进入观察状态,通过绑定到我们随后连接的同一个端口。此外,系统不会死锁,只有应用程序阻塞,因为它调用read(),等待从未写入的数据。