当前位置:首页 > 行业动态 > 正文

c并发服务器

并发服务器是一种能同时处理多个客户端请求的服务器,通过多线程、多进程或异步I/O实现。它提高了服务器性能和响应速度,适用于大量用户访问的场景。

C语言实现并发服务器主要有多线程和多进程两种方式,以下是详细介绍:

多线程并发服务器

1、原理:主线程负责接受客户端连接,一旦有新的客户端连接到服务器,就立即创建一个子线程,在子线程的线程处理函数中专门处理该客户端的读写请求。

2、代码示例

c并发服务器

服务器端

     #include <stdio.h>
     #include <stdlib.h>
     #include <sys/types.h>
     #include <sys/socket.h>
     #include <netinet/in.h>
     #include <string.h>
     #include <arpa/inet.h>
     #include <unistd.h>
     #include <pthread.h>
     #define ERRLOG(errmsg)                                       
         do                                                       
         {                                                        
             printf("%s--%s(%d):", __FILE__, __func__, __LINE__); 
             perror(errmsg);                                      
             exit(-1);                                            
         } while (0)
     typedef struct
     {
         int accept_fd;
         struct sockaddr_in client_addr;
     } num_t;
     int socket_bind_listen(const char *argv[]);
     void *task1(void *arg);
     int main(int argc, const char *argv[])
     {
         if (3 != argc)
         {
             printf("Usage : %s <IP> <PORT>
", argv[0]);
             exit(-1);
         }
         int sockfd = socket_bind_listen(argv);
         struct sockaddr_in client_addr;
         memset(&client_addr, 0, sizeof(client_addr));
         socklen_t client_addr_len = sizeof(client_addr);
         num_t ku;
         memset(&ku, 0, sizeof(ku));
         pthread_t tid;
         while (1)
         {
             ku.accept_fd = accept(sockfd, (struct sockaddr *)&client_addr, &client_addr_len);
             if (-1 == ku.accept_fd)
                 ERRLOG("accept error");
             printf("客户端 (%s:%d) 连接了
", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
             ku.client_addr = client_addr;
             if (pthread_create(&tid, NULL, task1, (void *)&ku))
                 ERRLOG("create tid2 error");
             pthread_detach(tid);
         }
         close(sockfd);
         return 0;
     }
     int socket_bind_listen(const char *argv[])
     {
         int sockfd = socket(AF_INET, SOCK_STREAM, 0);
         if (-1 == sockfd)
             ERRLOG("socket error");
         struct sockaddr_in server_addr;
         memset(&server_addr, 0, sizeof(server_addr));
         server_addr.sin_family = AF_INET;
         server_addr.sin_port = htons(atoi(argv[2]));
         server_addr.sin_addr.s_addr = inet_addr(argv[1]);
         if (-1 == bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)))
             ERRLOG("bind error");
         if (-1 == listen(sockfd, 128))
             ERRLOG("listen error");
         return sockfd;
     }
     void *task1(void *arg)
     {
         num_t *ku = (num_t *)arg;
         char buf[1024];
         int len;
         while (1)
         {
             len = read(ku->accept_fd, buf, sizeof(buf));
             if (len <= 0)
             {
                 printf("客户端断开连接
");
                 break;
             }
             printf("接收到来自客户端的消息: %s
", buf);
             write(ku->accept_fd, buf, len);
         }
         close(ku->accept_fd);
         return NULL;
     }

客户端

c并发服务器

     #include <stdio.h>
     #include <stdlib.h>
     #include <string.h>
     #include <sys/types.h>
     #include <sys/socket.h>
     #include <netinet/in.h>
     #include <arpa/inet.h>
     #include <unistd.h>
     #define DEST_PORT 9999 //目标地址端口号 
     #define DEST_IP "127.0.0.1" //目标地址IP,这里设为本机,不一定非得是127.0.0.1,只要127开头并且不是127.0.0.0和127.255.255.255即可
     #define MAX_DATA 100 //接收到的数据最大程度 
     int main()
     {
         int sockfd;
         struct sockaddr_in dest_addr;
         char buf[MAX_DATA];
         sockfd = socket(AF_INET, SOCK_STREAM, 0);
         dest_addr.sin_family = AF_INET;
         dest_addr.sin_port = htons(DEST_PORT);
         dest_addr.sin_addr.s_addr = inet_addr(DEST_IP);
         bzero(&(dest_addr.sin_zero), 8);
         connect(sockfd, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr));
         printf("connect success
");
         while (1)
         {
             char send_buf[512] = "";
             scanf("%s", &send_buf);
             write(sockfd, send_buf, sizeof(send_buf));
             read(sockfd, buf, sizeof(buf));
             printf("client receive:%s
", buf);
         }
         return 0;
     }

多进程并发服务器

1、原理:每个客户端连接由一个独立的进程处理,进程间相互隔离,互不影响,提高了稳定性,利用操作系统的进程管理和调度机制,实现并发处理。

2、代码示例

c并发服务器

服务器端

     #include <stdio.h>
     #include <stdlib.h>
     #include <string.h>
     #include <unistd.h>
     #include <sys/types.h>
     #include <sys/socket.h>
     #include <netinet/in.h>
     #include <arpa/inet.h>
     void handle_client(int client_socket) {
         char buffer[256];
         int n;
         bzero(buffer, 256);
         n = read(client_socket, buffer, 255);
         if (n < 0) perror("ERROR reading from socket");
         printf("Here is the message: %s
", buffer);
         n = write(client_socket, "I got your message", 18);
         if (n < 0) perror("ERROR writing to socket");
         close(client_socket);
     }
     int main(int argc, char *argv[]) {
         int sockfd, newsockfd, portno;
         socklen_t clilen;
         struct sockaddr_in serv_addr, cli_addr;
         if (argc < 2) {
             fprintf(stderr,"ERROR, no port provided
");
             exit(1);
         }
         sockfd = socket(AF_INET, SOCK_STREAM, 0);
         if (sockfd < 0) {
             perror("ERROR opening socket");
             exit(1);
         }
         bzero((char *) &serv_addr, sizeof(serv_addr));
         portno = atoi(argv[1]);
         serv_addr.sin_family = AF_INET;
         serv_addr.sin_addr.s_addr = INADDR_ANY;
         serv_addr.sin_port = htons(portno);
         if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
             perror("ERROR on binding");
             exit(1);
         }
         listen(sockfd, 5);
         clilen = sizeof(cli_addr);
         while (1) {
             newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
             if (newsockfd < 0) {
                 perror("ERROR on accept");
                 continue;
             }
             int pid = fork();
             if (pid < 0) {
                 perror("ERROR on fork");
                 close(newsockfd);
                 continue;
             }
             if (pid == 0) {  // child process
                 close(sockfd);
                 handle_client(newsockfd);
                 exit(0);
             } else {  // parent process
                 close(newsockfd);  // parent doesn't need this
             }
         }
         close(sockfd);
         return 0;  // this will never be executed
     }