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);   //子进程必须关闭listenfd
55             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     //创建socket
70     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     //创建socket
57     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 }

 

c网络编程(server服务器端,linux),古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。