对listen第二个参数的理解,及示例(windows版)

19 篇文章 2 订阅
10 篇文章 0 订阅

本文受了https://blog.csdn.net/yangbodong22011/article/details/60399728 的启发

对tcp的三次握手,我也不太明白。但是阐述listen函数的第二个参数的意义,可以用一个简单的例子来解释,用不到三次握手的知识:

长话短说。tcp服务器好比是一个机关单位,单位的领导好比是accept函数,只有accept函数返回了值,才算是客户端与服务器建立了联系。但是领导下面还有一个“传达室”,当领导不在时,传达室负责受理客户端发来的请求。当领导回来后,再把请求上报给领导,由领导盖章确认。listen函数的第二个参数-backlog,相当于是传达室一次最多能受理的申请数目。假如传达室受理的申请数目已经达到backlog的取值,那么再来到传达室的申请会被直接退回。对于客户端来说,一旦申请被受理,客户端程序就认为已经建立了连接(但是真实情况是,领导可能还没回家,只是申请被接收而已,连接建立只是一种假象,领导回家才算正式办理)。

看下面的代码:

#include "stdafx.h"
#include "TCPServer.h"


TCPServer *		g_pTCPServer = NULL;

UINT uiListenThread(LPVOID param)
{
	// 一直等待客户端
	TCPServer * pTCPServer = TCPServer::pGetInstance();
	pTCPServer->m_bThrdRunning = true;
	if(pTCPServer)
	{
		while (true)
		{
			pTCPServer->vListen();
			Sleep(60000);
		}
	}

	pTCPServer->m_bThrdRunning = false;
	return 0;
}

TCPServer::TCPServer(char * pIP, int iPort)
{
	m_pThrd = NULL;
	m_bThrdRunning = false; 
	m_iClientSock = -1;
	m_iLocalSock = -1;
	WSAData wsa;
	m_iRetWSA = WSAStartup(MAKEWORD(2,2), &wsa);
	g_pTCPServer = this;

	m_iLocalSock = iInit(pIP, iPort);
	if(m_iLocalSock > 0)
	{
		 m_pThrd = AfxBeginThread(uiListenThread,NULL);
	}
}

TCPServer::~TCPServer()
{
	if(m_bThrdRunning)
	{
		TerminateThread(m_pThrd, 0);
		m_bThrdRunning = false;
	}

	if(m_iClientSock > 0)
	{
		closesocket(m_iClientSock);
		m_iClientSock = -1;
	}

	if(m_iLocalSock > 0)
	{
		closesocket(m_iLocalSock);
		m_iLocalSock = -1;
	}

	WSACleanup();
}

int TCPServer::iInit(char * pIP, int iPort)
{
	int iSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	int iRet = -1;
	if(iSock > 0)
	{
		struct sockaddr_in local;
		local.sin_family = AF_INET;
		local.sin_port = htons(iPort);
		local.sin_addr.s_addr = inet_addr(pIP);

		int iLen = sizeof(local);

		if(bind(iSock, (struct sockaddr *)&local, iLen) >= 0)
		{
			if(listen(iSock, 1) == 0)
			{
				iRet = iSock;
			}
		}
	}

	return iSock;
}

void TCPServer::vListen(void)
{
	//addrClient 用于保存客户端的IP以及端口号
	struct sockaddr_in addrClient;
	int iLen = sizeof(addrClient);

	m_iClientSock = accept(m_iLocalSock, (struct sockaddr *)&addrClient, &iLen);
}

TCPServer * TCPServer::pGetInstance(void)
{
	return g_pTCPServer;
}

int TCPServer::iSend(char * pData, int iLen)
{
	if(m_iClientSock > 0 && m_iLocalSock > 0)
	{
		return send(m_iClientSock, pData, iLen, 0);
	}
	else
	{
		return 0;
	}
}

这里要注意两处:一是if(listen(iSock,1) == 0),1代表传达室最多受理一个申请。另一处是sleep(60000),就是说,每60秒调用一次accept函数(领导每60秒来一趟单位)。下面看下程序实际运行情况:

1)启动服务端程序,用网络助手建立一个客户端套接字,并与服务端相连;

2)这一次accept调用后,要过60秒才能调用下一次accept(领导不在家);

3)在下一个60秒到来前,网络助手建立第二个套接字,与服务端相连,也连上了(这就是前面说的假象,其实只是被传达受理)

4)在下一个60秒到来之前,网络助手建立第三个套接字,与服务端相连,连不上(因为传达室已经受理了一个申请尚未处理,而且(listen(iSock,1) == 0)),传达室最多受理一个;

5)60秒到来,触发accept函数,第二个客户端套接字才算真的连上(领导盖章了)

6)再次尝试第三个套接字的客户端连接,成功(传达室又能受理了。其实也是假象,原因同上)

7)60秒后又一次在accept处触发断点,第三个套接字才算真正连上。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值