首页 > 代码库 > c网络编程(server服务器端,linux)

c网络编程(server服务器端,linux)

多进程
 1 #include "network.h" 2  3 void do_service(int peerfd) 4 { 5     char recvbuf[1024] = {0}; 6     int ret; 7     while(1) 8     { 9         ret = readline(peerfd, recvbuf, 1024);10         if(ret == 0)11         {12             close(peerfd);13             exit(EXIT_SUCCESS);14         }15         //模拟数据处理过程16         printf("recv data: %s", recvbuf);17         writen(peerfd, recvbuf, strlen(recvbuf));18     }19 }20 21 void handler(int sig)22 {23     while(waitpid(-1, NULL, WNOHANG) > 0)24         ;25     return ;26 }27 28 29 int get_listen_fd();30 31 int main(int argc, const char *argv[])32 {33     if(signal(SIGPIPE, SIG_IGN) == SIG_ERR)34         ERR_EXIT("signal");35     if(signal(SIGCHLD, handler) == SIG_ERR)36         ERR_EXIT("signal");37     38     int listenfd = get_listen_fd();39 40 41     while(1)42     {43         struct sockaddr_in peeraddr;44         memset(&peeraddr, 0, sizeof(peeraddr));45         socklen_t len = sizeof peeraddr;46         int peerfd = accept(listenfd, (struct sockaddr *)&peeraddr, &len);47         if(peerfd == -1)48             ERR_EXIT("accpet");49         pid_t pid;50         if((pid = fork()) < 0)51             ERR_EXIT("fork");52         else if(pid == 0)53         {54             close(listenfd);   //子进程必须关闭listenfd55             do_service(peerfd);56             exit(EXIT_SUCCESS);57         }58 59         close(peerfd);  //这里必须关闭peerfd,否则导致资源耗尽60     }61     close(listenfd);62     return 0;63 }64 65 66 67 int get_listen_fd()68 {69     //创建socket70     int listenfd = socket(PF_INET, SOCK_STREAM, 0);71     if(listenfd == -1)72         ERR_EXIT("socket");73 74 75     //设置端口复用76     int on = 1;77     if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)78         ERR_EXIT("setsockopt");79 80     struct sockaddr_in servaddr;81     servaddr.sin_family = AF_INET;82     servaddr.sin_port = htons(8989);83     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);84     //bind端口85     if(bind(listenfd, (struct sockaddr*)&servaddr, sizeof servaddr) < 0)86         ERR_EXIT("bind"); 87 88     //listen端口89     if(listen(listenfd, SOMAXCONN) < 0)90         ERR_EXIT("listen");91 92     return listenfd;93 }

 

多线程
 1 #include "network.h" 2 #include <pthread.h> 3  4  5  6 void do_service(int peerfd); 7 int get_listen_fd(); 8 void *thread_func(void *arg); 9 10 int main(int argc, const char *argv[])11 {12     if(signal(SIGPIPE, SIG_IGN) == SIG_ERR)13         ERR_EXIT("signal");14     15     int listenfd = get_listen_fd();16 17     while(1)18     {19         int peerfd = accept(listenfd, NULL, NULL);20         if(peerfd == -1)21             ERR_EXIT("accpet");22         //每接受一个请求,就创建一个新的线程23 24         int *pfd = (int *)malloc(sizeof(int));25         if(pfd == NULL)26             ERR_EXIT("malloc");27         *pfd = peerfd;28         pthread_t tid;29         if(pthread_create(&tid, NULL, thread_func, pfd))30         {31             free(pfd); //确保内存不被泄露32         }33 34    }35     close(listenfd);36     return 0;37 }38 39 void *thread_func(void *arg)40 {41     int *pfd = (int *)arg;42     int peerfd = *pfd;43     free(pfd);44 45     pthread_detach(pthread_self()); //把自己设置为分离状态46 47     do_service(peerfd);48     close(peerfd);49 }50 51 52 53 54 int get_listen_fd()55 {56     //创建socket57     int listenfd = socket(PF_INET, SOCK_STREAM, 0);58     if(listenfd == -1)59         ERR_EXIT("socket");60 61 62     //设置端口复用63     int on = 1;64     if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)65         ERR_EXIT("setsockopt");66 67     struct sockaddr_in servaddr;68     servaddr.sin_family = AF_INET;69     servaddr.sin_port = htons(8989);70     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);71     //bind端口72     if(bind(listenfd, (struct sockaddr*)&servaddr, sizeof servaddr) < 0)73         ERR_EXIT("bind"); 74 75     //listen端口76     if(listen(listenfd, SOMAXCONN) < 0)77         ERR_EXIT("listen");78 79     return listenfd;80 }81 82 83 void do_service(int peerfd)84 {85     char recvbuf[1024] = {0};86     int ret;87     while(1)88     {89         ret = readline(peerfd, recvbuf, 1024);90         if(ret == 0)91         {92             close(peerfd);93             exit(EXIT_SUCCESS);94         }95         //模拟数据处理过程96         printf("recv data: %s", recvbuf);97         writen(peerfd, recvbuf, strlen(recvbuf));98     }99 }

头文件

 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <unistd.h> 5 #include <signal.h> 6 #include <errno.h> 7 #include <sys/types.h> 8 #include <sys/socket.h> 9 #include <netinet/in.h>10 #include <arpa/inet.h>11 12 #define ERR_EXIT(m) 13     do { 14         perror(m);15         exit(EXIT_FAILURE);16     }while(0)17 18 19 ssize_t readn(int fd, void *usrbuf, size_t n);20 ssize_t writen(int fd, void *usrbuf, size_t n);21 ssize_t recv_peek(int sockfd, void *usrbuf, size_t n);22 ssize_t readline(int sockfd, void *usrbuf, size_t maxline);
  1 #include "network.h"  2   3   4 ssize_t readn(int fd, void *usrbuf, size_t n)  5 {  6     size_t nleft = n; //表示还需要读取的字节数  7     ssize_t nread;  8     char *bufp = usrbuf; //控制read函数存放的位置  9  10     while(nleft > 0) 11     { 12         if((nread = read(fd, bufp, nleft)) == -1) 13         { 14             if(errno == EINTR)  //interupt 15                 nread = 0;  //continue;  中断需要再次读取 16             else 17                 return -1;  // ERROR 18         }else if(nread == 0)  // EOF 19             break; 20          21         nleft -= nread; 22         bufp += nread; 23     } 24     return (n - nleft); 25 } 26  27 ssize_t writen(int fd, void *usrbuf, size_t n) 28 { 29     size_t nleft = n; 30     ssize_t nwrite; 31  32     char *bufp = usrbuf; 33  34     while(nleft > 0) 35     { 36         //nwrite == 0也属于错误 37         if((nwrite = write(fd, bufp, nleft)) <= 0) 38         { 39             if(errno == EINTR) 40                 nwrite = 0; 41             else 42                 return -1; // -1 和 0 43         } 44  45         nleft -= nwrite; 46         bufp += nwrite; 47     } 48     return n;  //这里不是 n- nleft 必须是n 49 } 50  51 //recv_peek选项完成一次正确的读取过程。 52 ssize_t recv_peek(int sockfd, void *buf, size_t len) { 53     int nread; 54     while (1) { 55         //这个过程只成功调用一次 56         nread = recv(sockfd, buf, len, MSG_PEEK); 57         if (nread < 0 && errno == EINTR) {  //被中断则继续读取 58             continue; 59         } 60         if (nread < 0) { 61             return -1; 62         } 63         break; 64     } 65     return nread; 66 } 67  68  69 ssize_t readline(int sockfd, void *buf, size_t maxline) { 70     int nread;  //一次IO读取的数量 71     int nleft;  //还剩余的字节数 72     char *ptr;  //存放数据的指针的位置 73     int ret;    //readn的返回值 74     int total = 0;  //目前总共读取的字节数 75  76     nleft = maxline-1; 77     ptr = buf; 78  79     while (nleft > 0) { 80         //这一次调用仅仅是预览数据 81         //并没有真的把数据从缓冲区中取走 82         ret = recv_peek(sockfd, ptr, nleft); 83         //注意这里读取的字节不够,绝对不是错误!!! 84         if (ret <= 0) { 85             return ret; 86         } 87  88         nread = ret; 89         int i; 90         for (i = 0; i < nread; ++i) { 91             if (ptr[i] == \n) { 92                 //这里才是真正的读取过程 93                 ret = readn(sockfd, ptr, i + 1); 94                 if (ret != i + 1) { 95                     return -1; 96                 } 97                 total += ret; 98                 ptr += ret; 99                 *ptr = 0;100                 return total;   //返回此行的长度 ‘\n‘包含在其中101             }102         }103         //如果没有发现\n,这些数据应全部接收104         ret = readn(sockfd, ptr, nread);105         if (ret != nread) {106             return -1;107         }108         nleft -= nread;109         total += nread;110         ptr += nread;111     }112     *ptr = 0;113     return maxline-1;114 }