当前位置: 首页> 财经> 产业 > TCP并发服务器

TCP并发服务器

时间:2025/7/11 19:00:26来源:https://blog.csdn.net/qq_69639971/article/details/141649448 浏览次数:0次

多进程并发服务器

  1. 主进程监听:服务器在指定端口上监听客户端连接请求。
  2. 接受连接:当有新的客户端连接时,服务器接受该连接,并为其派生一个新的子进程。
  3. 进程处理:子进程独立运行,处理客户端的请求,直到客户端断开连接。子进程在处理过程中可以读取数据、进行处理,并返回结果。
  4. 进程终止:子进程处理完毕后终止,释放相关资源。
#include <head.h>int init_tcp_ser(const char *ip ,unsigned short port)
{	int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (-1 == sockfd){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 (-1 == ret){perror("fail bind");return -1;}ret = listen(sockfd, 128);if (-1 == ret){perror("fail listen");return -1;}return sockfd;
}void handler(int signo)
{wait(NULL);
}int main(int argc, const char *argv[])
{pid_t pid = 0;int connfd = 0;char buff[1024] = {0};signal(SIGCHLD, handler);int sockfd = init_tcp_ser("192.168.1.100", 50000);if (-1 == sockfd){return -1;}while (1){connfd = accept(sockfd, NULL, NULL);if (-1 == connfd){perror("fail accept");return -1;}pid = fork();if (pid > 0){}else if (0 == pid){while (1){memset(buff, 0, sizeof(buff));ssize_t size = recv(connfd, buff, sizeof(buff), 0);if (size <= 0){break;}printf("cli---> %s\n", buff);strcat(buff, "--->ok!");send(connfd, buff, strlen(buff), 0);}close(connfd);}}return 0;
}

多线程并发服务器

  1. 主线程监听:服务器在指定端口上监听客户端连接请求。
  2. 接受连接:当有新的客户端连接时,服务器接受该连接,并为其创建一个新的线程。
  3. 线程处理:新线程负责处理该客户端的所有请求,直到客户端断开连接。线程可以读取客户端发送的数据、进行处理,并将结果发送回客户端。
  4. 线程终止:在处理完毕后,线程可以选择继续等待新的请求(长连接)或终止(短连接)。
#include <head.h>int init_tcp_ser(const char *ip ,unsigned short port)
{	int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (-1 == sockfd){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 (-1 == ret){perror("fail bind");return -1;}ret = listen(sockfd, 128);if (-1 == ret){perror("fail listen");return -1;}return sockfd;
}void *do_communicate(void *arg)
{int connfd = *((int *)arg);char buff[1024] = {0};while (1){ssize_t size = recv(connfd, buff, sizeof(buff), 0);if (size <= 0){break;}printf("cli---> %s\n", buff);strcat(buff, "----->ok!");send(connfd, buff, strlen(buff), 0);}close(connfd);return NULL;
}int main(int argc, const char *argv[])
{pid_t pid = 0;int connfd = 0;pthread_t tid;char buff[1024] = {0};int sockfd = init_tcp_ser("192.168.1.163", 50000);if (-1 == sockfd){return -1;}while (1){connfd = accept(sockfd, NULL, NULL);if (-1 == connfd){perror("fail accept");return -1;}pthread_create(&tid, NULL, do_communicate, &connfd);pthread_detach(tid);}return 0;
}

IO模型

1.阻塞IO

#include <head.h>
int main(int argc, char *argv[])
{char buf[1024] = {0};mkfifo("./myfifo",0664);int fifofd = open("./myfifo",O_RDONLY);if(-1 == fifofd)handle_error("open fail");while(1){fgets(buf,sizeof(buf),stdin);printf("stdin: %s\n",buf);memset(buf,0,sizeof(buf));read(fifofd,buf,sizeof(buf));printf("fifo: %s\n",buf);}close(fifofd);return 0;
}

2.非阻塞IO

fcntl

  int fcntl(int fd, int cmd, ... /* arg */ );      

(1)功能:设置文件描述符属性 
(2)参数:

  • fd:文件描述符 
  • cmd:F_GETFL        获得文件描述符属性
  • F_SETFL        设置文件描述符属性 

(3)返回值:

  • F_GETFL:成功返回获得的属性;失败返回-1 
  • F_SETFL:成功返回0;失败返回-1 

O_NONBLOCK   非阻塞;O_ASYNC      异步方式        

#include <head.h>
int main(int argc, char *argv[])
{char buf[1024] = {0};mkfifo("./myfifo",0664);int fifofd = open("./myfifo",O_RDONLY);if(-1 == fifofd)handle_error("open fail");//获取文件原有属性int flag = fcntl(0,F_GETFL);//增加非阻塞属性  flag = flag | O_NONBLOCK;//去掉非阻塞属性//flag = flag & (~O_NONBLOCK);//设置属性fcntl(0,F_SETFL,flag);while(1){memset(buf,0,sizeof(buf));fgets(buf,sizeof(buf),stdin);printf("stdin: %s\n",buf);memset(buf,0,sizeof(buf));read(fifofd,buf,sizeof(buf));printf("fifo: %s\n",buf);}close(fifofd);return 0;
}

3.信号驱动IO

#include <head.h>void handle(int signo)
{char buf[1024] = {0};fgets(buf,sizeof(buf),stdin);printf("stdin: %s\n",buf);
}
int main(int argc, char *argv[])
{signal(SIGIO,handle);char buf[1024] = {0};mkfifo("./myfifo",0664);int fifofd = open("./myfifo",O_RDONLY);if(-1 == fifofd)handle_error("open fail");//获取文件原有属性int flag = fcntl(0,F_GETFL);flag = flag | O_ASYNC;fcntl(0,F_SETFL,flag);//关联当前进程fcntl(0,F_SETOWN,getpid());while(1){memset(buf,0,sizeof(buf));read(fifofd,buf,sizeof(buf));printf("fifo: %s\n",buf);}close(fifofd);return 0;
}

4.多路复用IO

1.select

int select(int nfds,  fd_set *readfds,  fd_set *writefds,  fd_set *exceptfds,  struct timeval *timeout);

(1)功能:监听文件描述符集合
(2)参数:

  • nfds:监测的文件描述符上限值(最大文件描述符的值+1)
  • readfds:读文件描述符集合
  • writefds:写文件描述符集合
  • exceptfds:异常条件的描述符集合
  • timeout:设置超时时间;NULL:一直等待            

(3)返回值:

  • 成功返回产生事件文件描述符个数
  • 失败返回-1 
  • 定时时间到达仍没有事件产生返回0 

       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 

#include <head.h>
int main(int argc, char *argv[])
{int maxfd = 0;char buf[1024] = {0};mkfifo("./myfifo",0664);int fifofd = open("./myfifo",O_RDONLY);if(-1 == fifofd)handle_error("open fail");//创建文件描述符集合fd_set rdfds;fd_set tmfds;//清空集合FD_ZERO(&rdfds);//添加关注的文件描述符到集合中FD_SET(0,&rdfds);maxfd = 0 > maxfd ? 0 : maxfd;FD_SET(fifofd,&rdfds);maxfd = fifofd > maxfd ? fifofd : maxfd;while(1){tmfds = rdfds;//开始监测集合中的ioint cnt = select(maxfd+1, &tmfds, NULL, NULL, NULL);if(cnt < 0)handle_error("select fail");//根据返回值的结果区分处理不同的ioif(FD_ISSET(0, &tmfds)){memset(buf, 0, sizeof(buf));fgets(buf, sizeof(buf), stdin);printf("stdin: %s\n",buf);}if(FD_ISSET(fifofd, &tmfds)){memset(buf,0,sizeof(buf));read(fifofd,buf,sizeof(buf));printf("fifo: %s\n",buf);}}close(fifofd);return 0;
}

2.poll

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

(1)功能:监听文件描述符集合中的事件
(2)参数:

  • ds:文件描述符集合事件数组首地址
  • nfds:事件个数
  • timeout:超时时间

(3)返回值:

  • 成功返回产生事件的文件描述符个数
  • 失败返回-1 
  • 超时时间到达仍没有产生事件返回0 
       struct pollfd {int   fd;         /* file descriptor */short events;     /* requested events */short revents;    /* returned events */};

3.epoll模型

(1)epoll_create

    int epoll_create(int size);

1)功能:创建一个监听事件表(内核中)
2)参数:size:监听事件最大个数
3)返回值:成功返回非负值:表示epoll事件表对象(句柄);失败返回-1         


(2)epoll_ctl

  int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

1)功能:在监听事件表中新增一个事件
2)参数:
        epfd:事件表文件描述符 
        op:         EPOLL_CTL_ADD        新增事件
                      EPOLL_CTL_MOD        修改事件 
                      EPOLL_CTL_DEL        删除事件
         fd:文件描述符 

         event:EPOLLIN  读事件;    EPOLLOUT    写事件

struct epoll_event {uint32_t     events;      /* Epoll events */epoll_data_t data;        /* User data variable */};

3)返回值:成功返回0 ;失败返回-1    

(3)epoll_wait

  int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

1)功能:监听事件表中的事件,并将产生的事件存放到结构体数组中
2)参数:

  • epfd:事件表文件描述符
  • events:存放结果事件结构体数组空间首地址 
  • maxevents:最多存放事件个数
  • timeout:超时时间; -1:阻塞等待直到有事件发生 

3)返回值:

  • 成功返回产生事件个数
  • 失败返回-1 
  • 超时时间到达没有事件发生返回0 
#include <head.h>
#include <sys/epoll.h>int epoll_add_fd(int epfds, int fd, uint32_t event)
{struct epoll_event ev;ev.events = event;ev.data.fd = fd;int ret = epoll_ctl(epfds, EPOLL_CTL_ADD, fd, &ev);if(-1 == ret)handle_error("epoll_ctl fail");return 0;
}
int epoll_del_fd(int epfds, int fd)
{int ret = epoll_ctl(epfds, EPOLL_CTL_DEL, fd, NULL);if(-1 == ret)handle_error("epoll_ctl fail");return 0;
}int main(int argc, char *argv[])
{int maxfd = 0;char buff[1024] = {0};mkfifo("./myfifo",0664);int fifofd = open("./myfifo", O_RDONLY);if(-1 == fifofd)handle_error("open fail");struct epoll_event evs[2];int epfds = epoll_create(2);if(-1 == epfds)handle_error("epoll_create fail");epoll_add_fd(epfds, 0, EPOLLIN);epoll_add_fd(epfds, fifofd, EPOLLIN);while(1){int cnt = epoll_wait(epfds, evs, 2, -1);if(cnt < 0)handle_error("epoll_wait fail");for(int i = 0; i < cnt; i++){if(0 == evs[i].data.fd){memset(buff, 0, sizeof(buff));fgets(buff, sizeof(buff), stdin);printf("STDIN: %s\n", buff);}else if(fifofd == evs[i].data.fd){memset(buff, 0, sizeof(buff));ssize_t size = read(evs[i].data.fd, buff, sizeof(buff));if(size < 0){epoll_del_fd(epfds, evs[i].data.fd);close(evs[i].data.fd);continue;}printf("FIFO: %s\n", buff);}}}return 0;
}

关键字:TCP并发服务器

版权声明:

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

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

责任编辑: