实例说明listen()函数第二个参数的意义与用法

我们先来看结果:

Client:

#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <arpa/inet.h>

int main(int argc,char** argv)
{
	int ret;
	int sockfd = socket(AF_INET,SOCK_STREAM,0);
	if (sockfd == -1)
	{
		printf("socket error\n");
		return -1;
	}

	struct sockaddr_in serveraddr;
	memset(&serveraddr,0,sizeof(serveraddr));
	serveraddr.sin_family = AF_INET;
	inet_aton(argv[1],&serveraddr.sin_addr);
	serveraddr.sin_port = htons((unsigned short)(atoi(argv[2])));
	
	ret = connect(sockfd,(const sockaddr*)&serveraddr,sizeof(serveraddr));
	if (ret == -1)
	{
		printf("connect error,ret = %d\n",ret);
		return -1;
	}
  
	for(;;)
	{}
	return 0;
}


Server:
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <arpa/inet.h>


int main(int argc,char** argv)
{
	int ret;
	int listenfd = socket(AF_INET,SOCK_STREAM,0);
	if (listenfd == -1)
	{
		printf("socket error\n");
		return -1;
	}

	struct sockaddr_in serveraddr;
	memset(&serveraddr,0,sizeof(serveraddr));
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
	serveraddr.sin_port = htons((unsigned short)(atoi(argv[1])));

	ret = bind(listenfd,(const sockaddr*)&serveraddr,sizeof(serveraddr));
	if (ret == -1)
	{
		printf("bind error,ret = %d\n",ret);
		return -1;
	}

  <span style="WHITE-SPACE: pre">	</span>int backlog = atoi(argv[2]);
	ret = listen(listenfd, backlog);
	printf("backlog = %d,ret =%d\n",backlog,ret);
	if (ret == -1)
	{
		printf("listen error,ret = %d\n",ret);
		return -1;
	}
	
	for(;;)
	{}
	return 0;
}
server的代码中通过命令行的方式传入backlog的值,以便于我们通过修改backlog来观察不同的backlog对程序的影响.

开启一个server与3个client.

backlog = 1时:



backlog = 2时:

观察上图,server在19890端口监听,3个client发起TCP连接。在第一幅图中,对client而言,3个状态均为established.对server而言,2个连接状态为established,一个为syn_recv.第二幅图中,对server而言,3个链接的状态均为established。

我们先来看一下TCP连接的状态转换



再说回listen(int fd,int backlog)函数,内核会为一个监听套接字维护两个队列,当有TCP请求到来时,即3次握手中的syn分节发送来时,会在未完成队列中增加一项,3次握手完成时,未完成队列中的项就移动到已完成队列里,accept()函数会从已连接队列里取走已完成连接.

这个backlog参数就是控制我们的已连接队列里等待accept()取走的连接的最大数目的.注意一点,backlog与这个已排队连接的最大数目未必是完全相等的,不同的系统的实现可能不同.比如backlog=1,系统允许的实际一排队数目可能为2.


所以在上图中,对client而言,connect()返回,TCP的状态就转变为established。而对server而言,3次握手完成TCP状态才会转换为established。在图一中,由于backlog参数的限制,导致有一条连接并未完成3次握手,所以状态为syn_recv。



在Tornado框架中,我们可以使用`Application`类的`add_handlers`方法来添加路由规则。在添加路由规则时,我们需要传递一个元组的列表,每个元组包含两个元素,第一个元素是一个正则表达式,第二个元素是一个`RequestHandler`类或其子类。 例如,我们可以在`Application`类中添加以下路由规则: ```python import tornado.ioloop import tornado.web class MyHandler(tornado.web.RequestHandler): def get(self): self.write("Hello, world") handlers = [ (r"/my-url/", MyHandler), ] app = tornado.web.Application(handlers) app.listen(8888) tornado.ioloop.IOLoop.current().start() ``` 在上面的代码中,我们创建了一个`MyHandler`类来处理`/my-url/`的请求,然后将该类与路由规则`(r"/my-url/", MyHandler)`绑定,最后创建了一个`Application`类实例并开始监听端口。 在视图函数中,我们可以使用`tornado.web.Application.reverse_url`方法生成对应的URL。例如,如果我们要生成`/my-url/`的URL,可以使用以下代码: ```python url = app.reverse_url("my-url") # url 现在的值是 '/my-url/' ``` 如果我们的路由规则中包含参数,例如: ```python class MyHandler(tornado.web.RequestHandler): def get(self, pk): self.write("Hello, world " + pk) handlers = [ (r"/my-url/(\d+)/", MyHandler), ] app = tornado.web.Application(handlers) app.listen(8888) ``` 那么我们可以在视图函数中传递参数来生成对应的URL: ```python url = app.reverse_url("my-url", 1) # url 现在的值是 '/my-url/1/' ``` 这样,我们就可以方便地引用我们在Tornado中定义的路由规则。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值