FTP 编写 3:同时为多个客户端服务(多线程)
在上篇文章中写了一个能连接的FTP,但是它只能为一个客户端进行服务,而我们知道在现实生活中我们见到的大部分网络应用都能同时为多个用户提供服务,所以接下来我们的目标是使用多线程来使服务端能同时为多个客户端进行服务。
C++ 多线程这个不是网络编程的内容,所以在这里不会详细讲解(其实我也不懂啊,刚看的书就来瞎写试试了),并且在这里使用的也不会太复杂(应该)。如果各位有对多线程有疑惑或者有兴趣,如果是计算机专业的并且学过操作系统的可以去看这本关于 C++ 多线程的书:《C++ Concurrency in Action》,这本书从浅入深地进行讲解,很详细,有了操作系统关于线程的知识就容易看懂,上手也比较容易,我就是看了这本书才有胆子试试水的。我也不知道如果没有看过操作系统看这个容易不,你们也可以去试一试,如果感觉困难的话看一看操作系统的线程部分,然后再看。
好了,也就不废话了,下面开始编写
服务端
首先对服务端进行编写,在上一篇的代码中进行修改添加。添加的部分是多线程部分。
首先我们需要把多线程部分和 vector 容器的头文件添加进来:
#include <thread>
#include <vector>
添加相应的变量,考虑到每有一个客户端进行连接我们就需要新开一个线程专门对其进行服务,是动态变化的,所以我们使用指针,并且将线程在后台进行运行,这样我们就不用再对其进行管理,它自个按照代码运行就行了。而考虑到指针的内存释放问题,我们使用 vector 容器将每个新建的线程指针进行保存,在程序结束的时候释放到其占用的内存,相应的代码如下:
//定义多线程指针,用于创建线程
std::thread* t;
//用于线程的管理,保存创建的多线程指针,程序结束时释放占用的内存
std::vector<std::thread*> tManage;
//创建新的线程,并加入容器中,并将线程后台运行
t = new std::thread(server, sAccept);//server是线程运行函数,sAccept是已经与客户端连接的套接字
tManage.push_back(t);
t->detach();
接下来是线程运行函数,就是上面线程创建中的 server:其主要的内容是在第一次连接时候发送连接的信息给客户端,就想上一篇文章中的那样,然后我们用一个无限循环,在循环里面接收客户端发送来的信息并打印出来,具体代码如下:
//多线程函数,创建的多线程运行此函数
void server(SOCKET s) {
SOCKET socket = s;
struct sockaddr_in ser, cli;//网络地址
int iSend, iRecv;
char buf[1024] = "I am a server";
//显示客户端的 IP 信息
char clibuf[20] = { '\0' };
inet_ntop(AF_INET, (void*)&cli.sin_addr, clibuf, 16);
std::cout << "Accept client IP:" << clibuf << ":" << ntohs(cli.sin_port) << std::endl;
//发送信息给客户端
iSend = send(socket, buf, sizeof(buf), 0);
if (iSend == SOCKET_ERROR) {
std::cout << "send() Failed\n";
}
else if (iSend == 0) {
std::cout << "send() Zero\n";
}
else {
std::cout << "Send byte:" << iSend << std::endl;
std::cout << "----------------------------------\n";
}
//使用循环不断接受客户端发送来的信息并显示