“一请求一线程”方式实现服务器
-
- 前言
- socket使用流程
-
- 实现思路
- netassist
- 小总结
- 第一版服务器
-
- 实现思路
- 出现的问题
- 第二版服务器
- 第三版服务器
-
- 使用线程
- 解决问题
- 关于fd
- 总结
- 附件
前言
由于资源消耗大、线程管理复杂、性能问题等原因,“一请求一线程”(多线程)已经被淘汰,现在我们多使用select、poll、epoll等IO多路复用技术实现网络IO。我们只讲解实现思路,并且为后面IO多路复用技术的文章打下基础。在看本文之前,可以先看一看 网络IO以及socket编程 这篇文章。
socket使用流程
在网络通信中,一定是使用socket。下面初始化socket的固定流程。
#include <netinet/in.h>
#include <stdio.h>
#include <sys/socket.h>
#include <errno.h>
#include <string.h>
int main()
{
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in sevaddr;
sevaddr.sin_family = AF_INET;
sevaddr.sin_addr.s_addr = htonl(INADDR_ANY);
sevaddr.sin_port = htons(2000);
if (bind(sockfd, (struct sockaddr*)&sevaddr, sizeof(struct sockaddr)) == –1) {
printf(\”bind failed: %s\\n\”,strerror(errno));
return –1;
}
listen(sockfd, 10);
printf(\”listen finished\\n\”);
getchar(); // 阻塞在这里
printf(\”exit\\n\”);
return 0;
}
实现思路
使用socket()创建一个sockfd,用于监听端口。第一个参数AF_INET表示使用IPV4协议族;第二个参数SOCK_STREAM创建流式套接字类型,即TCP;第三个参数0对于 SOCK_STREAM 类型的套接字,通常设置为0,表示使用默认的传输层协议。
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
使用bind()将创建的sockfd与本机端口进行绑定。看下面的代码,我们要给本地端口指定通信协议族、初始化网卡地址、初始化端口号、绑定fd和本机端口。INADDR_ANY,即0.0.0.0,指本机任意网卡;在计算机中,0~1023是默认的端口号,所以我们要指定的端口后须大于1023,这里我们给定的端口号是2000;接下来,我们使用bind()绑定,若函数返回-1,则绑定失败。
struct sockaddr_in sevaddr;
sevaddr.sin_family = AF_INET; //IPV4
sevaddr.sin_addr.s_addr = htonl(INADDR_ANY); //0.0.0.0
sevaddr.sin_port = htons(2000); // 0-1023
if (bind(sockfd, (struct sockaddr*)&sevaddr, sizeof(struct sockaddr)) == –1) {
printf(\”bind failed: %s\\n\”,strerror(errno));
return –1;
}
完成上面的步骤,我们就可以对端口进行监听了。
listen(sockfd, 10);
我们可以先对程序编译运行,我们可以看到受getchar()的影响,程序处于阻塞状态。 我们敲一下回车,程序退出。
现在,我们再打开一个新的终端,输入命令netstat -anop | grep 2000查看端口2000的使用情况。我们可以看到端口2000已经被使用。
或者,我们可以在第二个终端中运行该程序。编译器返回bind failed: Address already in use,很好,这表明端口已经被占用,这是我们想要看到的结果。
netassist
在这里,向大家安利netassist(网络调试助手),作为我们的客户端。这里我直接使用127.0.0.1(本地回环地址)作为我的远程主机地址。 现在,我们连接已经运行的程序。可以看到,连接成功了!
因为listen执行成功并且客户端已经连接,现在我们通过netstat查看端口状态。可以看到,产生了一个新的连接状态。
既然已经连接上了,那么是否可以发数据?当然可以了! 点击“发送”,看到netassist的右下角的TX从0变为20,表示发送了20字节的数据到server端。可是,我们在server端并没有看到发送的数据,可以确定的是server已经接收到了信息。因为,server端暂时不能将接收到的数据打印出来。
评论前必须登录!
注册