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