linux网络编程(二)高并发服务器
- 错误处理
- 高并发服务器
- 多进程并发服务器
- 客户端
错误处理
#include "wrap.h"int Bind(int fd, const struct sockaddr* sa, socklen_t salen)
{int ret;if ((ret = bind(fd, sa, salen)) < 0){perror("bind error:");exit(1);}return ret;}int Accept(int fd, struct sockaddr* sa, socklen_t* salenptr)
{int ret;again:if ((ret = accept(fd, sa, salenptr)) < 0){if ((errno == ECONNABORTED) || (errno == EINTR)){goto again;}else{perror("accept error:");exit(1);}}return ret;}int Socket(int family, int type, int protocol)
{int ret;if ((ret=socket(family, type, protocol)) == -1){perror("socket error:");exit(1);}return ret;
}int Listen(int fd, int backlog)
{int ret;if ((ret = listen(fd, backlog)) < 0){perror("listen error:");exit(1);}return ret;}pid_t Fork()
{pid_t pid;pid = fork();if (pid < 0){perror("pid error:");exit(1);}else if (pid == 0){//子进程return pid;}else{//主进程return pid;}}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;elsereturn -1;}return n;
}
高并发服务器
多进程并发服务器
使用多进程并发服务器时要考虑以下几点:
- 父进程最大文件描述个数(父进程中需要close关闭accept返回的新文件描述符)
- 系统内创建进程个数(与内存大小相关)
- 进程创建过多是否降低整体服务性能(进程调度)
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <strings.h>
#include <string.h>
#include <ctype.h>
#include <signal.h>
#include <arpa/inet.h>
#include <sys/wait.h>#include "wrap.h"
#define SERV_PORT 6666void* wait_child(int signo)
{while (waitpid(0, NULL, WNOHANG) > 0);return;
}int main()
{pid_t pid;int fsd,csd,n;char buf[BUFSIZ],clie_ip[BUFSIZ];struct sockaddr_in serv_addr,clie_addr;socklen_t clie_len;//创建套接字fsd = Socket(AF_INET, SOCK_STREAM, 0);bzero(&serv_addr,sizeof(serv_addr));serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(SERV_PORT);serv_addr.sin_addr.s_addr =htonl(INADDR_ANY) ;//绑定Bind(fsd,(struct sockaddr*)&serv_addr,sizeof(serv_addr));Listen(fsd, 128);while(1){clie_len = sizeof(clie_addr);//接受客户端 阻塞csd = Accept(fsd, (struct sockaddr*)&clie_addr, &clie_len);printf("client IP = %s , port = %d \n",inet_ntop(AF_INET,&clie_addr.sin_addr.s_addr, clie_ip,sizeof(clie_ip)),ntohs(&clie_addr.sin_port));pid = Fork();if (pid == 0){//子进程close(fsd);break;}else{close(csd);//安装信号,子进程结束回收signal(SIGCHLD,wait_child);}}//子进程 接受的客户端的小写字符转化成大写字符if (pid == 0){while (1){n = Read(csd, buf, sizeof(buf));if (n == 0){close(csd);return 0;}else if (n > 0){write(STDOUT_FILENO, buf, sizeof(buf));for (int i = 0; i < n; i++){//转化大写buf[i] = toupper(buf[i]);}write(csd, buf, n);}//清空数组memset(buf, 0, sizeof(buf));}}return 0;}
客户端
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <stdio.h>
#include <memory.h>#define CLIE_PORT 6666
#define CLIE_IP "118.178.192.222"int main()
{char buf[BUFSIZ] = {0};struct in_addr s; // IPv4地址结构体int cfd,ret,n;struct sockaddr_in addr;//客服端创建套接字cfd = socket(AF_INET,SOCK_STREAM,0);if (cfd == -1){perror("client error:");exit(1);}memset(&addr, 0, sizeof(addr));addr.sin_family = AF_INET;addr.sin_port = htons(CLIE_PORT);inet_pton(AF_INET, CLIE_IP,&addr.sin_addr.s_addr);ret =connect(cfd,(struct sockaddr *)&addr,sizeof(addr));if (ret <0){perror("connect error:");exit(1);}while (1){//从终端写入fgets(buf,sizeof(buf),stdin);write(cfd,buf,strlen(buf));n=read(cfd, buf, sizeof(buf));printf("n = %d",n);if(n==0){exit(1);}write(STDOUT_FILENO, buf, n);memset(buf, 0, sizeof(buf));}close(cfd);return 0;
}