在套接字编程中,listen()
和accept()
函数扮演着非常关键的角色,特别是在TCP服务器的建立和管理客户端连接请求中。下面我会分别解释这两个函数的功能和它们之间的区别。
listen() 函数
listen()
函数主要用于TCP服务器端。在服务器端已经通过socket()
创建了一个套接字并通过bind()
绑定了一个本地地址后,listen()
函数就被用来启用该套接字接受来自客户端的连接请求。
- 参数:
listen()
函数通常接受两个参数:套接字描述符和backlog。backlog参数定义了请求队列中最多可以有多少个客户端连接等待接受。 - 功能: 当调用
listen()
后,之前的套接字从一个主动套接字变为了一个被动套接字,这意味着它可以接受来自客户端的连接请求,但自己不会主动发起连接。
accept() 函数
在服务器调用listen()
后,accept()
函数被用来从已经建立的队列中接受一个客户端的连接请求。
- 参数:
accept()
函数通常接受三个参数:监听的套接字描述符、指向struct sockaddr的指针用于获取客户端的地址信息,以及地址结构的大小。 - 功能:
accept()
的工作是阻塞当前进程,直到一个客户端连接请求到达。一旦客户端连接建立,accept()
会返回一个新的套接字描述符,这个新的描述符用于与新连接的客户端进行通信。原来的套接字继续在listen()
状态下,接受其他的连接请求。
区别
总结来说,listen()
和accept()
的主要区别如下:
- 作用对象:
listen()
作用于一个未连接的套接字并使其能够接受连接请求,而accept()
是从监听队列中实际接受一个连接请求。 - 返回值:
listen()
不返回连接相关的信息;accept()
通过返回一个全新的套接字描述符,用于后续的数据交换。 - 功能:
listen()
仅仅是准备套接字接受连接请求,不参与实际的数据传输;accept()
则是开始了一个新的会话,用于具体的数据传输。
示例
假设我们正在创建一个简单的TCP服务器,我们先创建和绑定套接字,然后调用listen()
让套接字进入被动监听状态。当一个客户端尝试连接时,我们通过accept()
接受这个连接请求,并通过返回的新套接字与客户端进行通信。
cint sockfd, new_sockfd; // 套接字描述符 struct sockaddr_in host_addr, client_addr; // 地址结构 socklen_t sin_size; int yes = 1; sockfd = socket(PF_INET, SOCK_STREAM, 0); // 创建套接字 host_addr.sin_family = AF_INET; // 主机字节序 host_addr.sin_port = htons(12345); // 网络字节序的端口号 host_addr.sin_addr.s_addr = INADDR_ANY; // 自动填充IP memset(&(host_addr.sin_zero), '\0', 8); // 清零结构体剩余部分 bind(sockfd, (struct sockaddr *)&host_addr, sizeof(struct sockaddr)); // 绑定地址 listen(sockfd, 5); // 开始监听,队列长度为5 sin_size = sizeof(struct sockaddr_in); new_sockfd = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size); // 接受连接请求
通过这个示例,我们可以看到listen()
和accept()
在建立TCP服务器中的作用和区别。
2024年6月29日 12:07 回复