该文章描述如何创建一个传统的阻塞IO(输入/输出)模型在TCP网络编程中的使用。调用(如accept、recv和send)。
TCP的客户端和服务端交互流程的示意图:

-
创建套接字 (
socket()):-
socket(AF_INET, SOCK_STREAM, 0)`创建了一个 IPv4 的流套接字,用于 TCP 通信。
-
-
初始化服务器地址结构 (
sockaddr_in):-
设置协议族
AF_INET(IPv4)。 -
将地址设为
INADDR_ANY,意味服务器会监听所有网络接口。 -
将端口号设为 2000,使用
htons函数确保端口号在网络字节序。
-
-
绑定套接字 (
bind()):-
将创建的套接字绑定到初始化的地址和端口上。
-
-
监听连接 (
listen()):-
开始监听网络上的连接请求,
10代表可同时等待的最大连接请求数。
-
int main(){
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(struct sockaddr_in));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(2000);
if(-1 == bind(sockfd, (struct sockaddr*)&servaddr,sizeof(struct sockaddr ))){
printf("bind failed:%s\n", strerror(errno));
return -1;
}
listen(sockfd, 10);
struct sockaddr_in clientaddr;
socklen_t len = sizeof(clientaddr);
memset(&clientaddr, 0, len);//len = sizeof(struct sockaddr_in)
-
接受客户端连接。
-
接收来自客户端的数据,并将接收到的数据条数打印出来。
#if 0
\\客户端连接并recv
printf("accept , sockfd:%d\n", sockfd);
int clientfd = accept(sockfd,(struct sockaddr*)&clientaddr,&len);
printf("accept finshed, clientfd:%d\n", clientfd);
char buffer[1024] = {0};
int count = recv(clientfd, buffer, 1024, 0);
printf("recv count:%d", count);
-
accept可以多次接收客户端链接,但加while循环只能接受来自同一客户端的数据,并接收到数据后将其回送,send给第一个连接的客户端。直到对方的套接字已经正常关闭了连接(
recv返回0)。#elif 0 \\第一个客户端连接并重复接受回帧(多个客户端连接会卡在第一个recv) printf("accept before, sockfd:%d\n", sockfd); int clientfd = accept(sockfd,(struct sockaddr*)&clientaddr,&len); printf("accept finshed, clientfd:%d\n", clientfd); while(1){ char buffer[1024] = {0}; int count = recv(clientfd, buffer, 1024, 0); if(count == 0){ break; } printf("recv count:%d\n", count); send (clientfd, buffer, count, 0); printf("send buffer:%s\n", buffer); }一请求一线程的实现
-
对于每个接入的客户端,创建一个新线程来处理通信。
-
线程内部循环接收数据,并将接收到的数据发送回客户端。
-
getchar()等待,防止程序直接退出#else /*每传入一个listen fd,为每个clientfd创建一个新的线程*/ while(1){ printf("accept before, sockfd:%d\n", sockfd); int clientfd = accept(sockfd,(struct sockaddr*)&clientaddr,&len); if(clientfd == -1){ printf("accept failed! error:%s\n", strerror(errno)); continue; } printf("accept finished, clientfd: %d, IP: %s, PORT:%d\n", clientfd,inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port)); pthread_t thid; pthread_create(&thid, NULL, client_thread, &clientfd); } #endif getchar(); //close(clientfd); return 0;线程处理函数 (
client_thread) -
每个客户端连接都通过该函数在单独的线程中处理。
void *client_thread(void *arg) { int clientfd = *(int *)arg; while (1) { char buffer[1024] = {0}; int count = recv(clientfd, buffer, 1024, 0); if(count == 0){ close(clientfd); return NULL; } printf("recv count:%d\n", count); send(clientfd, buffer, count, 0);//recv同时send printf("send buffer:%s\n", buffer); } }
文章参考与<零声教育>的C/C++linux服务期高级架构系统教程学习: https://it.0voice.com/p/t_pc/course_pc_detail/camp_pro/course_2U9D57IzMfQsoiaMuokdvXYV11c
5213

被折叠的 条评论
为什么被折叠?



