欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 金融 > TCP并发服务器

TCP并发服务器

2025/3/11 14:34:52 来源:https://blog.csdn.net/2301_81322562/article/details/146149445  浏览:    关键词:TCP并发服务器

单循环服务器:服务器在同一时刻只能响应一个客户端的需求。

并发服务器:服务器在同一时刻可以响应多个客户端的需求。

构建TCP服务器的方法:

        IO多路复用的函数接口[select()  poll() epoll()] 

1.多进程实现TCP并发服务器

#include <stdio.h>
#include "head.h"#define LISTEN_CLI__MAX_CNT 1024int init_tcp_ser(const char *ip, unsigned short port)
{int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){perror("fail socket");return -1;}struct sockaddr_in ser;ser.sin_family = AF_INET;ser.sin_port = htons(port);ser.sin_addr.s_addr = inet_addr(ip);int ret = bind(sockfd, (struct sockaddr *)&ser, sizeof(ser));if (ret < 0){perror("fail bind");return -1;}ret = listen(sockfd, LISTEN_CLI__MAX_CNT);if (ret < 0){perror("fail listen");return -1;}return sockfd;
}void handler(int signum)
{wait(NULL);
}int main(int argc, const char *argv[])
{struct sockaddr_in cli;socklen_t clilen = sizeof(cli);signal(SIGCHLD, handler);int sockfd = init_tcp_ser("192.168.1.179", 50000);if (sockfd < 0){return -1;}while (1){int connfd = accept(sockfd, (struct sockaddr *)&cli, &clilen);if (connfd < 0){perror("fail accept");return -1;}pid_t pid = fork();if (pid > 0){}else if (0 == pid){char buff[1024] = {0};while (1){memset(buff, 0, sizeof(buff));size_t size = recv(connfd, buff, sizeof(buff), 0);if (size < 0){perror("fail recv");exit(1);}else if (0 == size) // closed{break;}printf("[%s : %d][%ld] %s\n", inet_ntoa(cli.sin_addr), ntohs(cli.sin_port), size, buff);strcat(buff, "--->ok");size = send(connfd, buff, strlen(buff), 0);if (size < 0){perror("fail send");exit(1);}}exit(0);}else{perror("fail fork");return -1;}}return 0;
}

2.多线程实现TCP并发服务器 

#include <stdio.h>
#include "head.h"#define LISTEN_CLI__MAX_CNT 1024int init_tcp_ser(const char *ip, unsigned short port)
{int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){perror("fail socket");return -1;}struct sockaddr_in ser;ser.sin_family = AF_INET;ser.sin_port = htons(port);ser.sin_addr.s_addr = inet_addr(ip);int ret = bind(sockfd, (struct sockaddr *)&ser, sizeof(ser));if (ret < 0){perror("fail bind");return -1;}ret = listen(sockfd, LISTEN_CLI__MAX_CNT);if (ret < 0){perror("fail listen");return -1;}return sockfd;
}void *do_communicate(void *arg)
{char buff[1024] = {0};int connfd = *(int *)arg;while (1){memset(buff, 0, sizeof(buff));size_t size = recv(connfd, buff, sizeof(buff), 0);if (size < 0){perror("fail recv");return NULL;}else if (0 == size){break;}printf("%s\n", buff);strcat(buff, "---->ok");size = send(connfd, buff, strlen(buff), 0);if (size < 0){perror("fail send");return NULL;}}return NULL;
}int main(int argc, const char *argv[])
{struct sockaddr_in cli;pthread_t tid;socklen_t clilen = sizeof(cli);int sockfd = init_tcp_ser("192.168.1.179", 50000);if (sockfd < 0){return -1;}while (1){int connfd = accept(sockfd, (struct sockaddr *)&cli, &clilen);if (connfd < 0){perror("fail accept");return -1;}pthread_create(&tid, NULL, do_communicate, &connfd);pthread_detach(tid);}return 0;
}

3.IO多路复用

 

方法:

函数接口: select()


   void FD_CLR(int fd, fd_set *set);
       将fd从文件描述符集合中清除
       
       int  FD_ISSET(int fd, fd_set *set);
       判断文件描述符fd是否仍在文件描述符集合中
       
       void FD_SET(int fd, fd_set *set);
       将fd加入文件描述符集合中
        
       void FD_ZERO(fd_set *set);
       文件描述符集合清0  

具体代码实现 :用select实现数据的接受(并发实现从管道读数据和从终端读数据)

#include <stdio.h>
#include "head.h"#define LISTEN_CLI__MAX_CNT 1024int init_tcp_ser(const char *ip, unsigned short port)
{int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){perror("fail socket");return -1;}struct sockaddr_in ser;ser.sin_family = AF_INET;ser.sin_port = htons(port);ser.sin_addr.s_addr = inet_addr(ip);int ret = bind(sockfd, (struct sockaddr *)&ser, sizeof(ser));if (ret < 0){perror("fail bind");return -1;}ret = listen(sockfd, LISTEN_CLI__MAX_CNT);if (ret < 0){perror("fail listen");return -1;}return sockfd;
}int main(int argc, const char *argv[])
{struct sockaddr_in cli;pthread_t tid;int maxfd = -1;char buff[1024] = {0};socklen_t clilen = sizeof(cli);int sockfd = init_tcp_ser("192.168.1.158", 50000);if (sockfd < 0){return -1;}fd_set tmpfds;fd_set rdfds;FD_ZERO(&rdfds);FD_SET(sockfd, &rdfds);maxfd = maxfd > sockfd ? maxfd : sockfd;while (1){tmpfds = rdfds;int cnt = select(maxfd+1, &tmpfds, NULL, NULL, NULL);if (cnt < 0){perror("fail select");return -1;}for (int i = 0; i <= maxfd; i++){if (FD_ISSET(i, &tmpfds)){if (i == sockfd){int connfd = accept(sockfd, (struct sockaddr *)&cli, &clilen);if (connfd < 0){perror("fail accept");continue;}FD_SET(connfd, &rdfds);maxfd = maxfd > connfd ? maxfd : connfd;printf("[%s : %d] online\n", inet_ntoa(cli.sin_addr), ntohs(cli.sin_port));}else{//connfdmemset(buff, 0, sizeof(buff));ssize_t size = recv(i, buff, sizeof(buff), 0);if (size < 0){perror("fail recv");FD_CLR(i, &rdfds);close(i);continue;}else if (0 == size){FD_CLR(i, &rdfds);close(i);continue;	}printf("%s\n", buff);strcat(buff, "----ok");size = send(i, buff, strlen(buff), 0);if (size < 0){perror("fail send");FD_CLR(i, &rdfds);close(i);continue;}}}}}return 0;
}

select()函数接口的不足处:

 

 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词