linux accept函数与三次握手没有半毛钱的关系------三次握手可能发生在调用accept函数之前

972 篇文章 329 订阅
148 篇文章 34 订阅

        想必大家对tcp三次握手已经乱熟于心了,  在很多地方, 描述三次握手的时候, 总把accept函数扯进去, 其实三次握手和accept函数没有半毛钱的关系。 在linux中, accept函数的作用是: 从已经完成连接的socket队列中取出一个socket,  如果没有已经完成连接的socket, 那么accepte函数就会阻塞。 所以, 三次握手可以发生在accept函数调用之前, 来看看吧。

        服务端程序为:

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <malloc.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <stdarg.h>
#include <fcntl.h>
#include <sys/types.h>  
#include <sys/wait.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>  
#include <signal.h>

int main()
{
    sockaddr_in servAddr;
    memset(&servAddr,0,sizeof(servAddr));
    servAddr.sin_family = AF_INET;
    servAddr.sin_addr.s_addr = INADDR_ANY;
    servAddr.sin_port = htons(8765);
	
	int iListenSocket = socket(AF_INET, SOCK_STREAM, 0);
    bind(iListenSocket, (sockaddr *)&servAddr, sizeof(servAddr));
    listen(iListenSocket,5);

	int i = 0;
    while(1)
    {
    	sockaddr_in clientAddr;
        socklen_t iSize = sizeof(clientAddr);
        memset(&clientAddr, 0, sizeof(clientAddr));

		getchar(); // 卡住

		int iConnSocket = accept(iListenSocket,(sockaddr*)&clientAddr, &iSize);
        if(iConnSocket < 0)
        {
            if(errno == EINTR || errno == ECONNABORTED)
        	{
            	continue;
        	}
            else
            {
                printf("accept error, server\n");
                return -1;
            }
        }

	    char szBuf[1024] = {0};
		snprintf(szBuf, sizeof(szBuf), "client ip[%s], index %d", inet_ntoa(clientAddr.sin_addr), ++i);
        write(iConnSocket, szBuf, strlen(szBuf) + 1);

		getchar();  // 卡住
		
		close(iConnSocket);
    }

	getchar();
	close(iListenSocket); 
    return 0;
}

       启动它, 可以看到, 在accept之前, 有getchar()阻塞, 我们让它阻塞, 不执行accept.

 

       客户端程序为:

#include <unistd.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <malloc.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <stdarg.h>
#include <fcntl.h>

int main()
{
    int sockClient = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in addrSrv;
    addrSrv.sin_addr.s_addr = inet_addr("10.100.70.140");
    addrSrv.sin_family = AF_INET;
    addrSrv.sin_port = htons(8765);
    int iRet = connect(sockClient, ( const struct sockaddr *)&addrSrv, sizeof(struct sockaddr_in));
	printf("connect iRet: %d\n", iRet);

	char szBuf[2048] = {0};
	iRet = recv(sockClient, szBuf, sizeof(szBuf) - 1 , 0); 
	printf("msg from server: %s\n", szBuf);
	
	getchar();
    close(sockClient);

    return 0;
}

        我们启动3个客户端, 从客户端的结果可以看到, connect函数返回了, 且都是0,  而且, 在服务端也可以看到3个ESTABLISHED状态的socket,   而且, 如果用tcpdump抓包, 还能看到9次握手的过程。 这充分说明, 在调用accept函数之前, 已经完成了完整的握手。

        到这里, 大家应该对accept函数有更清晰的认识了。

        建议大家试试上面的程序, 反正我已经试过了, 有点意思。

 

 

 

 

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值