云计算百科
云计算领域专业知识百科平台

手把手带你实现多线程服务器

“一请求一线程”方式实现服务器

    • 前言
    • 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()的影响,程序处于阻塞状态。 p1 我们敲一下回车,程序退出。 p 现在,我们再打开一个新的终端,输入命令netstat -anop | grep 2000查看端口2000的使用情况。我们可以看到端口2000已经被使用。 p2 或者,我们可以在第二个终端中运行该程序。编译器返回bind failed: Address already in use,很好,这表明端口已经被占用,这是我们想要看到的结果。 p3

netassist

在这里,向大家安利netassist(网络调试助手),作为我们的客户端。这里我直接使用127.0.0.1(本地回环地址)作为我的远程主机地址。 p4 现在,我们连接已经运行的程序。可以看到,连接成功了! p5 因为listen执行成功并且客户端已经连接,现在我们通过netstat查看端口状态。可以看到,产生了一个新的连接状态。 p6 既然已经连接上了,那么是否可以发数据?当然可以了! 点击“发送”,看到netassist的右下角的TX从0变为20,表示发送了20字节的数据到server端。可是,我们在server端并没有看到发送的数据,可以确定的是server已经接收到了信息。因为,server端暂时不能将接收到的数据打印出来。

赞(0)
未经允许不得转载:网硕互联帮助中心 » 手把手带你实现多线程服务器
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!