当前位置: 首页 > news >正文

移动端手机网站制作英文网站建设 济南

移动端手机网站制作,英文网站建设 济南,wordpress的多站点网站无法访问,网站的分析网络套接字编程(二) 文章目录 网络套接字编程(二)简易TCP网络程序服务端创建套接字服务端绑定IP地址和端口号服务端监听服务端运行服务端网络服务服务端启动客户端创建套接字客户端的绑定和监听问题客户端建立连接并通信客户端启动程序测试单执行流服务器的弊端 多进程版TCP网络…网络套接字编程(二) 文章目录 网络套接字编程(二)简易TCP网络程序服务端创建套接字服务端绑定IP地址和端口号服务端监听服务端运行服务端网络服务服务端启动客户端创建套接字客户端的绑定和监听问题客户端建立连接并通信客户端启动程序测试单执行流服务器的弊端 多进程版TCP网络程序捕捉SIGCHLD信号孙子进程提供网络服务 多线程版TCP网络服务线程池版TCP网络程序 在上一篇博客 网络套接字编程(一)-CSDN博客中利用套接字编程编写了简易的UDP网络程序本文我们再编写一个简易的TCP网络程序。 简易TCP网络程序 和上一篇博客中编写的UDP网络程序一样将TCP网络程序分为服务端和客户端分别封装成类然后定义类并调用类内函数进行TCP网络程序的初始化和启动完成简易的网络通信。本文编写的TCP网络程序的功能同样是客户端发送数据给服务端服务端将接收的数据回传给客户端。 服务端创建套接字 使用套接字编程进行网络通信第一步就是要创建套接字因此在服务端类内的初始化函数内部进行套接字的创建 enum {SOCKET_ERROR1 }; class TcpServer {public:void InitServer() {// 创建套接字_listensock socket(AF_INET, SOCK_STREAM, 0);if (_listensock 0){std::cerr create socket error: strerror(errno) std::endl;exit(SOCKET_ERROR);}}private:int _listensock; };socket函数的参数 TCP协议采用的是有连接的可靠的数据传输方式因此socket的类型应该为SOCK_STREAM这种有连接的可靠的流式数据。 服务端绑定IP地址和端口号 套接字编程进行网络通信时确定唯一主机的方式就是利用IP地址和端口号服务端必须要让众多客户端一定能找到因此服务端要进行IP地址和端口号的绑定。云服务同样不需要绑定指定IP地址在服务端类内的初始化函数内部进行绑定 enum {SOCKET_ERROR1,BIND_ERROR }; static const uint16_t default_port 8081;//端口号缺省值 class TcpServer {public:TcpServer(uint16_t port default_port):_port(port) {}void InitServer() {// 创建套接字_listensock socket(AF_INET, SOCK_STREAM, 0);if (_listensock 0){std::cerr create socket error: strerror(errno) std::endl;exit(SOCKET_ERROR);}// 绑定IP地址和端口号struct sockaddr_in local;memset(local, 0, sizeof(local));local.sin_family AF_INET;local.sin_addr.s_addr INADDR_ANY;local.sin_port htons(_port);if (bind(_listensock, (struct sockaddr *)local, sizeof(local)) 0){std::cerr bind socket error strerror(errno) std::endl;exit(BIND_ERROR);}} private:uint16_t _port;int _listensock; };云服务不需要绑定指定IP地址的原因 云服务不同于普通的主机可能存在许多张网卡因此云服务所使用的IP地址可能有许多个数据接收的IP地址不确定如果绑定云服务器某一指定IP地址进程就可能接收不到其他IP地址收到的数据。INADDR_ANY对应的常量值是0.0.0.0它表示绑定到所有可用的网络接口上即可以通过任何可用的IP地址进行通信云服务会把所有IP地址的得到的数据接收然后根据端口号传输给指定进程。 服务端监听 TCP协议是需要建立连接的由于建立连接的时机是不确定因此要让服务端处于准备建立连接的状态也就是然服务端进行监听让服务端监听需要用到listen函数 listen函数 //listen函数所在的头文件和函数声明#include sys/types.h #include sys/socket.hint listen(int sockfd, int backlog);该函数的功能是将指定的套接字设置为监听状态以便接受客户端的连接请求。用于TCP协议的服务端sockfd参数 套接字描述符用于标识一个已经打开的套接字。backlog参数 指定连接请求队列的最大长度。该参数决定了在调用accept函数之前能够排队等待处理的未完成连接请求的数量。返回值 成功时返回0表示操作成功。失败时返回-1并设置errno变量以指示具体的错误原因。 由于TCP协议需要在建立连接后进行网络通信而监听需要在建立连接前进行因此在服务端类内的初始化函数内部进行监听 enum {SOCKET_ERROR1,BIND_ERROR,LISTEN_ERROR }; static const uint16_t default_port 8081;//端口号缺省值 static const int backlog 32; class TcpServer {public:TcpServer(uint16_t port default_port):_port(port) {}void InitServer() {// 创建套接字_listensock socket(AF_INET, SOCK_STREAM, 0);if (_listensock 0){std::cerr create socket error: strerror(errno) std::endl;exit(SOCKET_ERROR);}// 绑定IP地址和端口号struct sockaddr_in local;memset(local, 0, sizeof(local));local.sin_family AF_INET;local.sin_addr.s_addr INADDR_ANY;local.sin_port htons(_port);if (bind(_listensock, (struct sockaddr *)local, sizeof(local)) 0){std::cerr bind socket error strerror(errno) std::endl;exit(BIND_ERROR);}// 监听if (listen(_listensock, backlog) 0){std::cerr listen socket error strerror(errno) std::endl;exit(LISTEN_ERROR);}} private:uint16_t _port;int _listensock; };服务端运行 服务端运行后第一步要做的就是获取和客户端的连接通过通过建立的连接进行网络通信获取连接需要使用accept函数 //accept函数所在的头文件和函数声明#include sys/types.h #include sys/socket.hint accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);该函数的功能是用于接受连接请求并建立连接。用于TCP协议的服务端sockfd参数 套接字描述符用于标识一个已经处于监听状态的套接字。addr参数 指向一个sockaddr结构体的指针用于存储客户端的地址信息。addrlen参数 指向一个整数的指针表示addr结构体的长度。返回值 成功时返回一个新的套接字的文件描述符用于与客户端进行通信。失败时返回-1并设置errno变量以指示具体的错误原因。 在服务端类内的启动函数内部进行连接的获取 class TcpServer {public:void StartServer()//服务端运行函数 {while (true){// 获取连接struct sockaddr_in peer;socklen_t len sizeof(peer);int sock accept(_listensock, (struct sockaddr *)peer, len);if (sock 0){std::cerr accept error std::endl;continue;}std::string clientip inet_ntoa(peer.sin_addr);uint16_t clientport ntohs(peer.sin_port);std::cout 获取连接成功: sock from _listensock , clientip - clientport std::endl;// 网络服务service(sock, clientip, clientport);}}private:uint16_t _port;int _listensock; };accept函数返回值 accept函数的返回值仍然是一个新的文件描述符该文件描述符指向的文件不同于创建套接字时的文件描述符指向的文件因为在TCP协议的套接字编程中创建套接字时的返回的文件是专门用于监听的而获取连接时返回的文件是用于和对应的建立连接的客户端通信的。 服务端网络服务 服务端运行起来后首先要建立连接然后要做的就是进行网络服务也就是进行数据的接收、数据的处理、数据的发送的任务因此在服务端类内的实现一个网络服务函数 static const uint16_t default_port 8081; using func_t std::functionstd::string(const std::string ); class TcpServer {public:TcpServer(func_t func, uint16_t port default_port):_func(func), _port(port) {}void service(int sock, std::string clientip, uint16_t clientport){std::string who clientip - std::to_string(clientport);char buffer[128];while (true){ssize_t n read(sock, buffer, sizeof(buffer) - 1); // 数据接收if (n 0){buffer[n] 0;std::string res _func(buffer);std::cout who res std::endl;write(sock, res.c_str(), res.size()); // 发送数据}else if (n 0){close(sock);std::cout client quit,me too std::endl;break;}else{close(sock);std::cout read error std::endl;break;}}}private:uint16_t _port;int _listensock;func_t _func;//数据处理方法 };网络服务中数据处理的方法由定义类对象的外部来进行传入。 使用read和write的原因 由于TCP协议采用的是流式数据传输因此可以使用read和write函数进行流式数据写入文件的缓冲区中然后操作系统会让调用驱动提供的读取和写入函数将数据从网卡中读取和写入然后网卡设备会将数据接收和发送。 服务端启动 调用服务端类内部的函数进行服务端的初始化并运行服务端。为了给错误运行服务端纠错引入了命令行参数在运行服务端时做纠错提示 enum {SOCKET_ERROR1,BIND_ERROR,LISTEN_ERROR,USAGE_ERROR };void Usage(const char *proc) {std::cout Usage:\n\t proc port\n std::endl; }std::string echo(const std::string message)//数据处理方法 {return message; }int main(int argc, char* argv[]) {if (argc ! 2){Usage(argv[0]);exit(USAGE_ERROR);}uint16_t port atoi(argv[1]);std::unique_ptrTcpServer tsvr(new TcpServer(echo, port));tsvr-InitServer();tsvr-StartServer();return 0; }数据处理方法的实现 由于本文实现的简易TCP网络程序中服务端的功能是将从客户端接收的数据回传给客户端因此数据处理方法的实现只是简单的将传入的数据返回即可。 客户端创建套接字 同样的将客户端封装成类在使用客户端时只需要创建类对象然后调用对应的函数即可使用客户端。在创建客户端类对象后的第一步就是初始化客户端在初始化客户端时首先就需要创建套接字 enum {SOCKET_ERROR1,BIND_ERROR,LISTEN_ERROR,USAGE_ERROR,CONNECT_ERROR }; class TcpClient {public: TcpClient(std::string serverip, uint16_t serverport):_serverip(serverip), _serverport(serverport) {}void InitClient(){//创建套接字_sock socket(AF_INET, SOCK_STREAM, 0);if (_sock 0){std::cerr create socket error: strerror(errno) std::endl;exit(SOCKET_ERROR);}}private:int _sock;std::string _serverip;uint16_t _serverport; };客户端的绑定和监听问题 同上一篇博客中所讲的一样为了避免端口号的冲突因此客户端无需自主绑定IP地址和端口号。 客户端是发起连接的一方建立连接的时机由客户端决定因此无需监听。 客户端建立连接并通信 由于使用TCP协议的网络通信前需要建立连接因此客户端也需要建立连接客户端需要使用connect函数 //connect函数所在的头文件和函数声明 #include sys/types.h #include sys/socket.hint connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);该函数的功能是发起连接请求并与服务器建立连接。用于TCP协议的客户端sockfd参数 套接字描述符用于标识一个已经打开的套接字。addr参数 指向一个sockaddr结构体的指针包含了服务器的地址信息。addrlen参数 表示addr结构体的长度。返回值 成功时返回0表示连接建立成功。失败时返回-1并设置errno变量以指示具体的错误原因。 客户端要想和服务端进行网络通信首先要建立连接然后进行网络通信因此在客户端类内部的运行函数中实现建立连接和网络通信 enum {SOCKET_ERROR1,BIND_ERROR,LISTEN_ERROR,USAGE_ERROR,CONNECT_ERROR }; class TcpClient {public: TcpClient(std::string serverip, uint16_t serverport):_serverip(serverip), _serverport(serverport) {}void StartClient(){//建立连接struct sockaddr_in peer;peer.sin_family AF_INET;peer.sin_addr.s_addr inet_addr(_serverip.c_str());peer.sin_port htons(_serverport);if (connect(_sock, (struct sockaddr*)peer, sizeof(peer)) 0){std::cerr connect socket error strerror(errno) std::endl;exit(CONNECT_ERROR);}std::string message;char buffer[128];while(true){std::cout Please enter;getline(std::cin, message);write(_sock, message.c_str(), message.size());int n read(_sock, buffer, sizeof(buffer)-1);if (n 0){std::cout server echo# message std::endl;}else if (n 0)//服务端关闭{std::cout server quit std::endl;break;}else{std::cout write error std::endl;break;}}}private:int _sock;std::string _serverip;uint16_t _serverport; };客户端启动 同样的调用客户端类内部的函数进行客户端的初始化并运行客户端。为了给错误运行客户端纠错引入了命令行参数在运行客户端时做纠错提示 void Usage(const char *proc) {std::cout Usage:\n\t proc serverip serverport\n std::endl; }int main(int argc, char *argv[]) {if (argc ! 3){Usage(argv[0]);exit(USAGE_ERROR);}std::string serverip argv[1];uint16_t serverport atoi(argv[2]);std::unique_ptrTcpClient tpcr(new TcpClient(serverip, serverport));tpcr-InitClient();tpcr-StartClient();return 0; }程序测试 本地测试 在命令行输入指令启动服务端并加上要指定端口号使用netstat -natp指令查看服务端的状态 服务端现处于监听状态等待客户端的连接然后进行网络服务。 启动客户端时输入IP地址127.0.0.1和端口号8081 服务端获取到了连接知晓了客户端的IP地址和端口号客户端建立了连接可以开始发送消息。 使用客户端发送数据 服务端能够将接受的数据回传给客户端。 关闭客户端 关闭客户端后read函数返回值为0服务端会断开与该客户端的服务但是服务端并没有停止运行。 网络测试 网络测试主要查看能否成功建立网络连接即可其余现象和本地测试现象相同在启动客户端时输入服务端所处的IP地址 单执行流服务器的弊端 使用两个客户端连接服务器后两个客户端都显示了连接成功等待输入数据但是服务端只获取了一个客户端的连接信息 两个客户端都向服务端发送数据只有一个客户端能得到服务端的网络服务得到回传的数据 关闭正在接收网络服务的客户端后客户端才能获取另一个客户端的连接并且给该客户端提供网络服务 单执行流的服务器 通过测试可以看到这服务端只有服务完一个客户端后才会服务另一个客户端。这个服务器一次只能为一个客户端提供服务是一个单执行流的服务端。 服务端需要获取连接才能够给对应的客户端提供网络服务因此正在接收网络服务的客户端关闭其他客户端才能接收网络服务。 客户端为什么会显示连接成功 服务端处于监听状态后客户端调用connect函数就可以与服务端建立连接不受服务端是否获取连接的影响。 解决方法 单执行流的服务器一次只能给一个客户端提供服务但是这样的服务端利用率是极低的要解决这个问题就需要将服务器改为多执行流的此时就要引入多进程或多线程。 多进程版TCP网络程序 多进程版与单执行流的服务端的区别在于当服务端获取连接后将执行网络服务的任务交给子进程或孙子进程去处理父进程依旧保持监听并获取连接这样可以有多个客户端都可以接收网络服务。根据对回收子进程的策略不同分为捕捉SIGCHLD信号版的和孙子进程提供网络服务版的。 捕捉SIGCHLD信号 至于捕捉SIGCHLD信号的多进程版的代码改动相对简单只需要在服务端运行函数中添加创建子进程让子进程进行网络服务的部分 class TcpServer {public:void StartServer(){signal(SIGCHLD, SIG_IGN);//修改信号处理动作while (true){// 获取连接struct sockaddr_in peer;socklen_t len sizeof(peer);int sock accept(_listensock, (struct sockaddr *)peer, len);if (sock 0){std::cerr accept error std::endl;continue;}std::string clientip inet_ntoa(peer.sin_addr);uint16_t clientport ntohs(peer.sin_port);std::cout 获取连接成功: sock from _listensock , clientip - clientport std::endl;// 网络服务pid_t id fork();//创建子进程if (id 0) // 服务器过载{close(sock); // 无法承担任务因此关闭文件continue;}else if (id 0){close(_listensock);//避免错误写入service(sock, clientip, clientport);exit(0);}close(sock);}}private:uint16_t _port;int _listensock;func_t _func; // 数据处理方法 };子进程能够完成网络服务的原理 父进程的文件描述符表会被子进程所继承也就是拷贝父进程的文件描述符表因此父进程打开的文件子进程也能够访问。子进程执行网络服务代码时可以对执行网络通信的文件进行读写操作即可完成网络服务的任务。 文件描述符表的关闭操作 执行网络服务的子进程关闭用于监听的文件描述符的原因是避免错误的读写操作。 父进程关闭获取连接所得的文件描述符的原因是父进程不进行网络服务不需要使用该文件描述符而文件描述符是有限的必须关闭避免文件描述符泄露。 子进程回收策略 父进程调用signal函数将SIGCHLD的处理动作置为SIG_IGN,这样fork出来的子进程在终止时会自动清理掉,不会产生僵尸进程,也不会通知父进程。 程序测试 使用两个客户端连接服务端 两个客户端现在可以同时接收网络服务了。 可以看到服务端为这个两个客户端都创建了子进程进行网络服务 客户端关闭后系统自动回收了进入僵尸状态的子进程 孙子进程提供网络服务 孙子进程提供网络服务和捕捉SIGCHLD信号在代码层面上改动如下 class TcpServer {public:void StartServer(){while (true){struct sockaddr_in peer;socklen_t len sizeof(peer);int sock accept(_listensock, (struct sockaddr *)peer, len);if (sock 0){std::cerr accept error std::endl;continue;}std::string clientip inet_ntoa(peer.sin_addr);uint16_t clientport ntohs(peer.sin_port);std::cout 获取连接成功: sock from _listensock , clientip - clientport std::endl;pid_t id fork();if (id 0) {close(sock); continue;}else if (id 0){close(_listensock);if (fork() 0) exit(0);//修改语句service(sock, clientip, clientport);exit(0);}close(sock);waitpid(id, nullptr, 0);//修改语句std::cout id 子进程等待成功 std::endl;//修改语句}}private:uint16_t _port;int _listensock;func_t _func; };孙子进程完成网络服务的原理 孙子进程完成网络服务的原理和子进程完成网络服务的原理相同孙子进程会拷贝子进程的文件描述符表孙子进程能够访问获取连接时得到的文件因此孙子进程具有完成网络服务的能力。 子进程和孙子进程的回收机制 子进程在创建完孙子进程后就会退出此时父进程立刻就能回收子进程并接着完成接下来的监听和获取连接的任务。 孙子进程会在子进程死后变成孤儿进程由系统回收。 程序测试 启动两个客户端连接服务端 可以看到客户端连接服务端成功后服务端立刻回收了子进程并且网络服务交给了孙子进程进行处理孙子进程由于父进程终止孙子进程的父进程ID变成为1也就是被操作系统接管了。 将客户端都退出后孙子进程由于执行结束也被操作系统回收了 多线程版TCP网络服务 相比单执行流服务端多线程版TCP网络服务中服务端会在获取连接后让其他线程完成网络服务任务只需要在服务端运行函数中添加创建线程执行网路服务任务即可 class TcpServer; class ThreadData//线程执行所需数据 {public:ThreadData(int sock, const std::string clientip, uint16_t clientport, TcpServer *ts):_sock(sock), _clientip(clientip), _clientport(clientport), _ts(ts) {}int _sock;std::string _clientip;uint16_t _clientport;TcpServer *_ts; };class TcpServer {public:void StartServer(){while (true){// 获取连接struct sockaddr_in peer;socklen_t len sizeof(peer);int sock accept(_listensock, (struct sockaddr *)peer, len);if (sock 0){std::cerr accept error std::endl;continue;}std::string clientip inet_ntoa(peer.sin_addr);uint16_t clientport ntohs(peer.sin_port);std::cout 获取连接成功: sock from _listensock , clientip - clientport std::endl;// 网络服务pthread_t tid;ThreadData *td new ThreadData(sock, clientip, clientport, this);pthread_create(tid, nullptr, threadRoutine, td);}}static void *threadRoutine(void *args)//线程执行函数{pthread_detach(pthread_self());ThreadData *td static_castThreadData*(args);td-_ts-service(td-_sock, td-_clientip, td-_clientport);delete td;return nullptr;}private:uint16_t _port;int _listensock;func_t _func; };线程是否需要关闭监听套接字的文件描述符 子进程会拷贝父进程的文件描述符表因此子进程关闭任一文件描述符不影响父进程但线程不同于进程一个进程内部的多个线程共享同一份数据包括文件描述符表线程关闭监听套接字的文件描述符会影响主线程监听因此线程无需关闭监听套接字的文件描述符。 线程回收机制 默认情况下新创建的线程退出后需要对其主动进行回收操作否则无法释放资源从而造成系统泄漏。但我们将线程分离当线程退出时自动释放线程资源。 程序测试 启动两个客户端连接服务端 可以看到服务端为两个客户端分别创建一个线程分别为它们执行网络服务。 关闭客户端系统会自动回收终止的线程 线程池版TCP网络程序 引入线程池 引入线程池的作用是为了减少创建线程的开销提高主机的效率。线程池的编写主播在另一边博客Linux]线程池-CSDN博客中有更详细的说明。 在线程池里面有一个任务队列当有新的任务到来的时候就可以将任务Push到线程池当中在线程池当中我们默认创建了5个线程这些线程不断检测任务队列当中是否有任务如果有任务就拿出任务然后调用该任务对应的Run函数对该任务进行处理如果线程池当中没有任务那么当前线程就会进入休眠状态。 #include iostream #include unistd.h #include pthread.h #include vector #include queueconst int N 5; // 线程池内线程数量template class T class ThreadPool { public:ThreadPool(int num N) : _num(num){pthread_mutex_init(_mutex, nullptr);pthread_cond_init(_cond, nullptr);}void LockQueue(){pthread_mutex_lock(_mutex);}void UnLockQueue(){pthread_mutex_unlock(_mutex);}void threadWait(){pthread_cond_wait(_cond, _mutex);}void threadWakeUP(){pthread_cond_signal(_cond);}T getTask(){T t _tasks.front();_tasks.pop();return t;}bool isEmpty(){return _tasks.empty();}static void *threadRoutine(void *args){pthread_detach(pthread_self());ThreadPoolT *tp static_castThreadPoolT *(args);while (true){tp-LockQueue();while (tp-isEmpty()){tp-threadWait();}T t tp-getTask();tp-UnLockQueue();t.Run();}}void Start(){pthread_t tid;for (int i 0; i _num; i){pthread_create(tid, nullptr, threadRoutine, this);}}void PushTask(T task) // 添加任务{LockQueue();_tasks.push(task);threadWakeUP();UnLockQueue();}~ThreadPool(){pthread_mutex_destroy(_mutex);pthread_cond_destroy(_cond);}private:int _num; // 线程数std::queueT _tasks; // 任务队列pthread_mutex_t _mutex; // 保证互斥访问任务队列这一共享资源pthread_cond_t _cond; // 根据任务队列中的任务数量控制线程的等待和运行 };引入任务类 由于线程池是用模板类编写的因此可以编写一个任务类传入线程池任务类中需要有获取连接得到的文件描述符、客户端IP、客户端端口号用于完成网络服务并且任务类需要实现Run函数供线程池调用另外还实现了service函数实现网络服务的具体实现 #include iostream #include unistd.hvoid service(int sock, std::string clientip, uint16_t clientport)//网络服务 {std::string who clientip - std::to_string(clientport);char buffer[128];while (true){ssize_t n read(sock, buffer, sizeof(buffer) - 1); // 数据接收if (n 0){buffer[n] 0;std::cout who buffer std::endl;write(sock, buffer, n); // 发送数据}else if (n 0){close(sock);std::cout client quit,me too std::endl;break;}else{close(sock);std::cout read error std::endl;break;}} }class Task { public:Task(int sock, std::string clientip, uint16_t clientport):_sock(sock), _clientip(clientip), _clientport(clientport){}void Run()//提供给线程池调用{service(_sock , _clientip, _clientport);}private:int _sock;std::string _clientip;uint16_t _clientport; };服务端实现 服务端类实现中需要将任务类引入并使用具体代码如下 enum {SOCKET_ERROR 1,BIND_ERROR,LISTEN_ERROR,USAGE_ERROR }; static const uint16_t default_port 8081; static const int backlog 32; class TcpServer {public:TcpServer(uint16_t port default_port) : _port(port) {}void InitServer(){// 创建套接字_listensock socket(AF_INET, SOCK_STREAM, 0);if (_listensock 0){std::cerr create socket error: strerror(errno) std::endl;exit(SOCKET_ERROR);}// 绑定IP地址和端口号struct sockaddr_in local;memset(local, 0, sizeof(local));local.sin_family AF_INET;local.sin_addr.s_addr INADDR_ANY;local.sin_port htons(_port);if (bind(_listensock, (struct sockaddr *)local, sizeof(local)) 0){std::cerr bind socket error strerror(errno) std::endl;exit(BIND_ERROR);}// 监听if (listen(_listensock, backlog) 0){std::cerr listen socket error strerror(errno) std::endl;exit(LISTEN_ERROR);}}void StartServer(){ThreadPoolTask tp;tp.Start();while (true){// 获取连接struct sockaddr_in peer;socklen_t len sizeof(peer);int sock accept(_listensock, (struct sockaddr *)peer, len);if (sock 0){std::cerr accept error std::endl;continue;}std::string clientip inet_ntoa(peer.sin_addr);uint16_t clientport ntohs(peer.sin_port);std::cout 获取连接成功: sock from _listensock , clientip - clientport std::endl;// 网络服务Task t(sock, clientip, clientport);tp.PushTask(t);}}private:uint16_t _port;int _listensock; };程序测试 启动服务端并且启动一个任务监视窗口输入指令while :; do ps -aL | head -1 ps -aL | grep tcp_server; sleep 1; done不断监视线程 可以看出在启动服务端后立刻就为线程池创建了5个线程等待任务。 启动客户端连接服务端进行网络通信 值得注意的是无论现在有多少客户端发来请求在服务端都只会有线程池当中的5个线程为之提供服务线程池当中的线程个数不会随着客户端连接的增多而增多这些线程也不会因为客户端的退出而退出。
http://www.tj-hxxt.cn/news/143752.html

相关文章:

  • 生物网站模板wordpress没有样式
  • 芜湖做网站哪家好产品设计培训机构哪家好
  • asp网站介绍闵行区怎么样
  • 昆明制作企业网站二级域名免费解析
  • 企业网站模板下载做网络销售如何找客户
  • 网站界面(ui)设计形考任务1猎头公司排名前十
  • 推进网站建设网站建设的行业市场的特点
  • 深圳做h5网站设计长沙网站公司网站建设
  • 网站中的滑动栏怎么做的重庆建设工程信息查询系统官网
  • h5哪个网站可以做青岛网站建设哪家公司好
  • 重庆网上商城网站建设公司网站建设管理员
  • 政务公开和网站建设英文网页设计欣赏
  • 织梦影视网站源码软件工程师是做什么的
  • 建设建材网站费用什么网站做谷歌联盟好
  • 网站建设在哪里招聘微信公众平台注册公众号
  • 大港建站公司5118网站是免费的吗
  • 官方网站开发商seo搜索引擎优化期末考试
  • wordpress 多站点 插件做男女的那个视频网站
  • 淘宝放单网站开发网页怎么认证
  • 企业网站建设三个原则推广的渠道和方法有哪些
  • 昆明网站建设网站网站流量检测
  • 做木工的网站嵌入式软件开发和软件开发的区别
  • 网站的建设服务器免费追剧的app下载
  • 建材外贸网站建设备案中心查网站
  • 建立网站的步骤及费用有经验的手机网站建设
  • 网站设计方法成都网站建设开发
  • 电子商务网站建设也管理电子产品首页网站版模
  • 17网站一起做网店优势与劣势天津河西做网站哪家好
  • 百度怎样注册免费的网站广东搜索seo哪家强
  • php做网站半成品wordpress首页调用短代码