栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

socket自连接

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

socket自连接

同时打开

两个应用程序同时彼此执行主动打开的情况是可能的,但是发生的可能性极小。每一方必须发送一个SYN,且这些SYN必须传递给对方。这需要每一方使用一个对方熟知的端口作为本地端口。这又称为同时打开。两端必须几乎在同时启动,以便收到彼此的SYN。只要两端有较长的往返时间就能保证这一点。
TCP是特意设计为了可以处理同时打开,对于同时打开它仅建立一条连接而不是两条连接(其他的协议族,最突出的是OSI运输层,在这种情况下将建立两条连接而不是一条连接)出现同时打开的情况时,两端几乎在同时发送SYN,并进入 SYN_SENT状态。当每一端收到SYN时,状态变为SYN_RCVD,同时它们都再发SYN并对收到的SYN进行确认。当双方都收到SYN及相应的ACK时,状态都变迁为ESTABLISHED。
在同时打开的情况下,即使客户端没有开启监听依然会建立连接。

自连接原因

看完同时打开应该明白了为什么会出现子连接,当客户端调用connect连接自身ip时,此时内核随机分配一个端口给客户端(这里并不是真正的随机而是通过计数器来实现的)(其范围可通过sys -A|grep range来查看),若此时分配的端口号等于目的端口号,则会出现自连接。
客户端发送syn后等待服务器返回ack,而此时客户端发的syn报文从网卡绕了一圈又回到了内核被自己收到,而此时客户端只会认为这个报文是另一台机器发过来的,触发‘同时打开’,发送ack报文,ack报文发送回来后 ,客户端认为是自己发送的第一条请求发回来了,就成功建立起连接,而以后的传输报文都被客户端看成是与服务器同时发的情况,所以ack报文还是能正常收发。

解决办法

1、监听端口设置在客户端ip_local_port范围外
2、建立连接后判断是否是自连接(getsockname、getpeername)

测试代码
#include
#include
#include
#include
#include
#include
#include
#include
int main(int args,char*argv[])
{
        if(args<3){printf("using ip and portn");return -1;}
        struct hostent* h;
        struct sockaddr_in clientaddr,servaddr;
        if((h = gethostbyname(argv[1]))==NULL)
        {
        	printf("gethostbyname failed:%sn",strerror(errno));
        	return -1;
        }
        servaddr.sin_family = AF_INET;
        servaddr.sin_port = htons(atoi(argv[2]));
        memcpy(&servaddr.sin_addr,h->h_addr,h->h_length);
        int socklen = sizeof(struct sockaddr_in);
        int sockfd;
        int n = 65536;
        int min,max;
        min = max = 50000;
        while(n--)
        {
	        memset(&clientaddr,0x00,sizeof(clientaddr));
	        sockfd = socket(AF_INET,SOCK_STREAM,6);
	        if(sockfd<0){printf("socket failedn");continue;}
	        if(connect(sockfd,(struct sockaddr*)&servaddr,sizeof(clientaddr))!=0)
	        {
	        	if(getsockname(sockfd,(struct sockaddr*)&clientaddr,(socklen_t*)&socklen)!=0)	
	        	{printf("%sn",strerror(errno)); close(sockfd);return -1;}
	        	min = minhtons(clientaddr.sin_port)?max:htons(clientaddr.sin_port);
	        	printf("connect failed(%d)n",ntohs(clientaddr.sin_port));
	        	close(sockfd);
	        	continue;
	        }
	        if(getsockname(sockfd,(struct sockaddr*)&clientaddr,(socklen_t*)&socklen)!=0)
	        {printf("%sn",strerror(errno)); close(sockfd);return -1;}
	        printf("connect success(%d)n",ntohs(clientaddr.sin_port));
	        break;
        }
        printf("min=%d,max=%dn",min,max);
        if(n<0)return -1;
        char buffer[10];
        for(int i =0;i<10;++i)
        {buffer[i] = "0123456789ABCDEF"[i%16];}
        int iret;
        for(int i = 0;i<2;++i)
        {
                iret = send(sockfd,buffer,sizeof(buffer),0);
                if(iret<0){printf("send failed:%sn",strerror(errno));close(sockfd);return -1;}
                if(iret==0){printf("close connectn");close(sockfd);}
                printf("发送:%sn",buffer);
                iret = recv(sockfd,buffer,sizeof(buffer),0);
                if(iret<0){printf("recv failed:%sn",strerror(errno));close(sockfd);return -1;}
                if(iret==0){printf("close connectn");close(sockfd);}
                printf("接收:%sn",buffer);
        }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/309265.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号