C|网络编程-C语言实现多进程并发服务器

在Linux操作系统下,服务器通过fork()复制已调用的进程来创建子进程,以此来实现多进程并发服务器
功能:客户端发送任意字符串,服务器端将字符串小写转大写toupper(); 并返回给客户端,客户端将结果打印在屏幕上。
C/S模型:
server.c 7 步:
socket();
bind();
listen();
accept();
read();
write();
close();
client.c 7 步:
socket();
connect()
fgets();
write(); 写给服务器
read(); 从服务器读
write(STDOUT_FILENO, buf, n);
close();
client.c

#include #include #include #include #include #include "wrap.h"#define SERV_IP "127.0.0.1" #define SERV_PORT 8000int main(void) { int sfd, len; struct sockaddr_in serv_addr; char buf[BUFSIZ]; sfd = Socket(AF_INET, SOCK_STREAM, 0); bzero(&serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; inet_pton(AF_INET, SERV_IP, &serv_addr.sin_addr.s_addr); serv_addr.sin_port = htons(SERV_PORT); Connect(sfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); while (1) { fgets(buf, sizeof(buf), stdin); int r = Write(sfd, buf, strlen(buf)); //printf("Write r === %d\n", r); len = Read(sfd, buf, sizeof(buf)); //printf("Read len == %d\n", len); Write(STDOUT_FILENO, buf, len); }Close(sfd); return 0; }

server.c
#include #include #include #include #include #include #include #include #include "wrap.h"#define MAXLINE 8192 #define SERV_PORT 8000void do_sigchild(int num) { while (waitpid(0, NULL, WNOHANG) > 0) ; }int main(void) { struct sockaddr_in servaddr, cliaddr; socklen_t cliaddr_len; int listenfd, connfd; char buf[MAXLINE]; char str[INET_ADDRSTRLEN]; int i, n; pid_t pid; struct sigaction newact; newact.sa_handler = do_sigchild; sigemptyset(&newact.sa_mask); newact.sa_flags = 0; sigaction(SIGCHLD, &newact, NULL); listenfd = Socket(AF_INET, SOCK_STREAM, 0); int opt = 1; setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(SERV_PORT); Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); Listen(listenfd, 20); printf("Accepting connections ...\n"); while (1) { cliaddr_len = sizeof(cliaddr); connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len); pid = fork(); if (pid == 0) { Close(listenfd); while (1) { n = Read(connfd, buf, MAXLINE); if (n == 0) { printf("the other side has been closed.\n"); break; } printf("received from %s at PORT %d\n", inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)), ntohs(cliaddr.sin_port)); for (i = 0; i < n; i++) buf[i] = toupper(buf[i]); Write(STDOUT_FILENO, buf, n); Write(connfd, buf, n); } Close(connfd); return 0; } else if (pid > 0) { Close(connfd); }else perr_exit("fork"); } return 0; }

另外,我自主封装了wrap库文件,用于在函数内部处理出错问题,并且仅使函数的首字母大写,这样在Linux操作系统vim的NORMAL模式下按K仍能进入帮助文档。
wrap.h
#ifndef __WRAP_H_ #define __WRAP_H_void perr_exit(const char *s); int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr); int Bind(int fd, const struct sockaddr *sa, socklen_t salen); int Connect(int fd, const struct sockaddr *sa, socklen_t salen); int Listen(int fd, int backlog); int Socket(int family, int type, int protocol); ssize_t Read(int fd, void *ptr, size_t nbytes); ssize_t Write(int fd, const void *ptr, size_t nbytes); int Close(int fd); ssize_t Readn(int fd, void *vptr, size_t n); ssize_t Writen(int fd, const void *vptr, size_t n); ssize_t my_read(int fd, char *ptr); ssize_t Readline(int fd, void *vptr, size_t maxlen); #endif

【C|网络编程-C语言实现多进程并发服务器】wrap.c
#include #include #include #include #include void perr_exit(const char *s) { perror(s); exit(-1); }int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr) { int n; again: if ((n = accept(fd, sa, salenptr)) < 0) { if ((errno == ECONNABORTED) || (errno == EINTR)) goto again; else perr_exit("accept error"); } return n; }int Bind(int fd, const struct sockaddr *sa, socklen_t salen) { int n; if ((n = bind(fd, sa, salen)) < 0) perr_exit("bind error"); return n; }int Connect(int fd, const struct sockaddr *sa, socklen_t salen) { int n; if ((n = connect(fd, sa, salen)) < 0) perr_exit("connect error"); return n; }int Listen(int fd, int backlog) { int n; if ((n = listen(fd, backlog)) < 0) perr_exit("listen error"); return n; }int Socket(int family, int type, int protocol) { int n; if ((n = socket(family, type, protocol)) < 0) perr_exit("socket error"); return n; }ssize_t Read(int fd, void *ptr, size_t nbytes) { ssize_t n; again: if ( (n = read(fd, ptr, nbytes)) == -1) { if (errno == EINTR) goto again; else return -1; } return n; }ssize_t Write(int fd, const void *ptr, size_t nbytes) { ssize_t n; again: if ( (n = write(fd, ptr, nbytes)) == -1) { if (errno == EINTR) goto again; else return -1; } return n; }int Close(int fd) { int n; if ((n = close(fd)) == -1) perr_exit("close error"); return n; }/*?????‰: ?o”èˉ¥èˉ???–????-—è????°*/ ssize_t Readn(int fd, void *vptr, size_t n) { size_tnleft; //usigned int ?‰??????aèˉ???–????-—è????° ssize_t nread; //int ???é?…èˉ???°????-—è????° char*ptr; ptr = vptr; nleft = n; while (nleft > 0) { if ((nread = read(fd, ptr, nleft)) < 0) { if (errno == EINTR) nread = 0; else return -1; } else if (nread == 0) break; nleft -= nread; ptr += nread; } return n - nleft; }ssize_t Writen(int fd, const void *vptr, size_t n) { size_t nleft; ssize_t nwritten; const char *ptr; ptr = vptr; nleft = n; while (nleft > 0) { if ( (nwritten = write(fd, ptr, nleft)) <= 0) { if (nwritten < 0 && errno == EINTR) nwritten = 0; else return -1; }nleft -= nwritten; ptr += nwritten; } return n; }static ssize_t my_read(int fd, char *ptr) { static int read_cnt; static char *read_ptr; static char read_buf[100]; if (read_cnt <= 0) { again: if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) { if (errno == EINTR) goto again; return -1; } else if (read_cnt == 0) return 0; read_ptr = read_buf; } read_cnt--; *ptr = *read_ptr++; return 1; }ssize_t Readline(int fd, void *vptr, size_t maxlen) { ssize_t n, rc; charc, *ptr; ptr = vptr; for (n = 1; n < maxlen; n++) { if ( (rc = my_read(fd, &c)) == 1) { *ptr++ = c; if (c== '\n') break; } else if (rc == 0) { *ptr = 0; return n - 1; } else return -1; } *ptr= 0; return n; }

    推荐阅读