Linux下网络编程之自定义协议进行并发多客户端与服务器的通信(多进程处理并发)不足占用资源太多

xiaoxiao2021-02-28  123

自定义协议消息体 *********msg.h*************#ifndef _MSG_H_#define _MSG_H_struct msg{ char head[10]; //头部 char msg_chck; //效验码 char buff[512];//体部}Msg;extern int write_msg(int socktf, char* buff, size_t len); extern int read_msg(int socktf, char* buff, size_t len); *****msg.c***************#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <sys/types.h> #include <memory.h> #include <unistd.h> #include "msg.h" /*计算校验码 */ static unsigned char msg_check(Msg* message) { //将头部和体部进行累加 unsigned char s = 0; int i; for(i = 0; i < sizeof(message->head); ++i) { s += message->head[i]; } for(i = 0; i < sizeof(message->buff); ++i) { s += message->buff[i]; } return s; } /* * 发送一个基于自定义协议的message * 发送的数据存放在buff中*/ int write_msg(int socktf, char* buff, size_t len) { Msg message; memset(&message, 0, sizeof(message)); strcpy(message.head, "wc2017000"); memcpy(message.buff, buff, len); message.checknum = msg_check(&message); //发送一个message消息 if(write(socktf, &message, sizeof(message)) != sizeof(message)) { return -1; } } /* * 读取一个基于兹定于协议的message * 读取的数据存在在buff中 */ int read_msg(int socktf, char* buff, size_t len) { Msg message; memset(&message, 0, sizeof(message)); size_t size; if(( size = read(socktf, &message, sizeof(message))) < 0 ) { return -1; } else if(size == 0) //数据读光了 { return 0; } //进行效验码验证,判断接受到message数据是否完整 unsigned char s = msg_check(&message); if(s == (unsigned char)message.checknum && (!strcmp("wc2017000", message.head))) { memcpy(buff, message.buff, len); return sizeof(message); } return -1; }客户端:/* * 文 件 名:time_tcp_client.cpp * 作 者:wc * 邮 件:plysten@gmail.com * 版 权:Copyright (c) 完全自由 * 意 图: */ #include <sys/socket.h> #include <sys/types.h> #include <arpa/inet.h> #include <netinet/in.h> #include <netdb.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <memory.h> #include <unistd.h> int main(int argc, char* argv[]) { if(argc < 3) printf("usage: %s ip port\n", argv[0]); exit(1); /*步骤1:创建socket套接字 * * */ int sockfd = socket(AF_INET, SOCK_STREAM, 0); if(sockfd < 0) { perror("socket error"); exit(1); } /*往serveraddr中填入ip,port和地址族类型 ipv4 * */ struct sockaddr_in serveraddr; memset(&serveraddr, 0, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; serveraddr.sin_port = htons(atoi(argv[2])); /*p地址转换为网络字节序后填入tuserveraddr中*/ inet_pton(AF_INET, argv[1], &serveraddr.sin_addr.s_addr); /*步骤2:客户端调用connect函数连接到服务器端 * */ if(connect(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0) { // perror("connect error); exit(1); } /*步骤3:调用IO函数(read/write)和服务器端进行双向通信 * */ char buff[512]; size_t size; char* prompt = ">"; while(1) { memset(buff, 0, sizeof(buff)); write(STDOUT_FILENO, prompt, 1); //连接提示服 size = read(STDIN_FILENO, buff, sizeof(buff)); if(size < 0) continue; buff[size-1] = '\0'; if(write_msg(sockfd, buff, sizeof(buff)) < 0 ) { perror("write msg error"); continue; } else if(read_msg(sockfd, buff, sizeof(buff)) < 0) { perror("read msg error"); } else { printf("buff:%s", buff); } } } /*步骤4: *关闭套接字socket * */ close(sockfd); return 0; } 服务器:/* * 文 件 名:time_tcp_server.cpp * 作 者:wc * 版 权:Copyright (c) 完全自由 * 意 图:study */ #include <netdb.h> #include <sys/socket.h> #include<netinet/in.h> #include <sys/un.h> #include <unistd.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <memory.h> #include <signal.h> #include <time.h> #include <arpa/inet.h> #include "msg.h" #include <errno.h> #include <wait.h> int sockfd; void sig_handler(int signo)//信号捕捉函数 { if(signo == SIGINT) { printf("server close\n"); //关闭socket close(sockfd); // exit(1); } if(signo == SIGCHLD) { perror("sigchld deaed"); wait(0); } } /*输出连接上来的客户端相关信息 * */ void out_addr(struct sockaddr_in* clientaddr) { /*将端口从网络字节序转换成主机字节序 * */ int port = ntohs(clientaddr->sin_port); char ip[16]; memset(ip, 0, sizeof(ip)); /*将ip地址从网络字节序转换成点分十进制*/ inet_ntop(AF_INET, &clientaddr->sin_addr.s_addr, ip, sizeof(ip)); printf("client: %s(%d) connectd\n", ip, port); } void do_service(int fd) { /*和客户端进行读写操作(双向通信) */ char buff[512]; while(1) { memset(buff, 0, sizeof(buff)); printf("start read and wirte...\n"); size_t size; if((size = read_msg(fd, buff, sizeof(buff))) < 0) { perror("protocal erorr"); break; } else if(size == 0) { break; } else { printf("%s\n", buff); if(write_msg(fd, buff, sizeof(buff)) < 0) { //if(error == EPIPE) // break; } perror("protacal error"); } } } int main(int argc, char* argv[]) { if(argc < 2) //外部输入参数监听 端口 { printf("usage %s #port\n", argv[0]); // exit(1); } if(signal(SIGINT, sig_handler) == SIG_ERR) //信号处理函数 { perror("signal sigint error"); // exit(1); } if(signal(SIGCHLD, sig_handler) == SIG_ERR) //信号处理函数 { perror("signal sigchld error"); // exit(1); } /*步骤1:创建socket(套接字) *socket创建在内核中,是一个结构体 *AF_INET: IPV4 *SOCK_STREAM: tcp协议 */ sockfd = socket(AF_INET, SOCK_STREAM, 0); /*步骤2:调用bind函数将socket和地址 * (包括ip、port)进行绑定 */ struct sockaddr_in serveraddr; //网络基本地址族 memset(&serveraddr, 0, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; //ipv4 serveraddr.sin_port = htons(atoi(argv[1]));//整数转换为网络字节序 prot serveraddr.sin_addr.s_addr = INADDR_ANY; //获取所有网卡客户端对应连接的请求 if(bind(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0) { perror("bind error"); exit(1); } /*步骤3:调用listen函数启动监听(指定port监听) * 通知系统去接受来自客户端的连接请求 * 将接收到的客户端连接请求放置到对应的队列中 * 第二个参数 客户端队列的长度 */ if(listen(sockfd, 10) < 0) { perror("lisen error"); exit(1); } /*步骤4:调用accept函数从队列(先进先出)中获 * 取一个客户端的请求连接,并返回新的socket描述符 * 注意:若没有客户端连接,调用此函数后阻塞,直到获得一个客户端的连接 */ struct sockaddr_in clientaddr; socklen_t clientlen = sizeof(clientaddr); while(1) { int fd = accept(sockfd, (struct sockaddr*)&clientaddr, &clientlen);//sockfd此时是新的客户但套接字的描述符 if(fd < 0) { perror("acdept error"); continue; } /*步骤5:调用IO函数(read/write)和连接额度客户端进行双向的通信 *启动子进程去调用IO函数(read/write)和连接的客户端进行双向的通信 (并发处理来自客户端的请求启动多进程 当一个新的客户端父进程new出一个子进程,父进程继续等待下个客户端的连接 ) */ pid_t pid = fork(); //创建一个进程 if(pid < 0) continue; else if(pid == 0)//子进程 { out_addr(&clientaddr); do_service(fd); close(fd);//内存在有计数器的 根据close的数量达到2的时候内存会释放的 break; } else//父进程 close(fd); } return 0; }
转载请注明原文地址: https://www.6miu.com/read-61031.html

最新回复(0)