C 客户端完成消息传递后,服务器无法退出接受循环
使用fork创建客户端程序以读取多个文件并创建单独的套接字。然后,每个套接字将其读取的文件中的消息发送到服务器,服务器使用fork处理多个客户端。但是,服务器永远不会退出accept循环,因此即使客户端上的所有套接字都关闭了,它也不会终止 服务器:C 客户端完成消息传递后,服务器无法退出接受循环,c,sockets,tcp,C,Sockets,Tcp,使用fork创建客户端程序以读取多个文件并创建单独的套接字。然后,每个套接字将其读取的文件中的消息发送到服务器,服务器使用fork处理多个客户端。但是,服务器永远不会退出accept循环,因此即使客户端上的所有套接字都关闭了,它也不会终止 服务器: #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h&g
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
#include "uthash.h" //Used for building hash map
#define PORT "3400"
#define HOST "localhost"
#define MAXDATASIZE 20
#define DEPARTMENT_LEN 2
#define BACKLOG 5
int main(void){
int sockfd, rv, child, numBytes;
int opt = 1;
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr; //connector's address information
socklen_t sin_size;
struct sigaction sa;
char dept[MAXDATASIZE];
double gpa;
char dept_name[DEPARTMENT_LEN + 1];
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if((rv = getaddrinfo(HOST, PORT, &hints, &servinfo)) != 0){
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
//loop though all the results and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next){
if((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1){
perror("server: socket");
continue; //move to next available socket
}
//reuse port and supress address already in use warnings
if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)) == -1){
perror("server: setsockopt");
exit(1);
}
//Bind socket and local address
if(bind(sockfd, p->ai_addr, p->ai_addrlen) == -1){
close(sockfd);
perror("server: bind");
continue;
}
break;
}
if(p == NULL){
fprintf(stderr, "server: failed to bind\n");
return 1;
}
freeaddrinfo(servinfo); //free list structure
//Listen to client
if(listen(sockfd, BACKLOG) == -1){
perror("server: listen");
exit(1);
}
//Reap all dead processes
sa.sa_handler = sigchild_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if(sigaction(SIGCHLD, &sa, NULL) == -1){
perror("sigaction");
exit(1);
}
while(1){//accept() main loop
sin_size = sizeof(their_addr);
if((child = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1){
perror("server: accept");
continue;
}
if(!fork()){//this is the child process
close(sockfd);
while(1){
if((numBytes = recv(child, dept, MAXDATASIZE, 0)) == -1){
perror("server: recv");
exit(1);
}
dept[numBytes] = '\0';
if(strcmp(dept, ":exit") == 0){
printf("%s\n", dept);
break;
}
else{
//printf("%s\n", dept);
_parse_dept(dept, dept_name, &gpa);
//printf("%s: %.1f\n", dept_name, gpa);
_add_dept(dept_name, gpa);
// _print_dept();
bzero(dept_name, (int)strlen(dept_name));
bzero(dept, (int)strlen(dept));
}
}//end while
//_print_dept();
printf("%d\n", 2);
close(child);
exit(0);
}// end fork
printf("%d\n", 3);
close(child); //parent doesn't need this
}
printf("%d\n", 4);
//_print_dept();
// _delete_all();
return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括“uthash.h”//用于构建哈希映射
#定义端口“3400”
#定义主机“localhost”
#定义MAXDATASIZE 20
#定义部门2
#定义待办事项5
内部主(空){
int sockfd,rv,child,numBytes;
int opt=1;
结构addrinfo提示,*servinfo,*p;
struct sockaddr\u存储它们的地址;//连接器的地址信息
袜子的大小;
struct-sigaction-sa;
char dept[MAXDATASIZE];
双gpa;
字符部门名称[部门名称+1];
memset(&hints,0,sizeof(hints));
hits.ai_family=AF_unsec;
hits.ai_socktype=SOCK_流;
hits.ai_flags=ai_被动;
if((rv=getaddrinfo(主机、端口、提示和服务信息))!=0){
fprintf(标准,“getaddrinfo:%s\n”,gai_strerror(rv));
返回1;
}
//循环遍历所有结果并绑定到第一个结果
for(p=servinfo;p!=NULL;p=p->ai_next){
if((sockfd=socket(p->ai_系列,p->ai_socktype,p->ai_协议))=-1){
perror(“服务器:套接字”);
继续;//移动到下一个可用套接字
}
//重用已在使用的端口和Superss地址警告
if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR | SO_REUSEPORT,&opt,sizeof(opt))=-1){
perror(“服务器:setsockopt”);
出口(1);
}
//绑定套接字和本地地址
如果(绑定(sockfd,p->ai_addr,p->ai_addrlen)=-1){
关闭(sockfd);
perror(“服务器:绑定”);
持续
}
打破
}
if(p==NULL){
fprintf(stderr,“服务器:绑定失败\n”);
返回1;
}
freeaddrinfo(servinfo);//自由列表结构
//听取客户的意见
如果(侦听(sockfd,BACKLOG)=-1){
perror(“服务器:监听”);
出口(1);
}
//收获所有死亡的过程
sa.sa_handler=sigchild_handler;
sigemptyset(和sa.sa_面具);
sa.sa_标志=sa_重启;
if(sigaction(SIGCHLD,&sa,NULL)=-1){
佩罗尔(“sigaction”);
出口(1);
}
while(1){//accept()主循环
sin_size=sizeof(其地址);
if((child=accept(sockfd,(struct sockaddr*)及其地址和大小))=-1){
perror(“服务器:接受”);
持续
}
如果(!fork()){//这是子进程
关闭(sockfd);
而(1){
if((numBytes=recv(child,dept,MAXDATASIZE,0))=-1){
perror(“服务器:recv”);
出口(1);
}
部门[numBytes]='\0';
如果(strcmp(dept,“:exit”)==0){
printf(“%s\n”,部门);
打破
}
否则{
//printf(“%s\n”,部门);
_分析部门(部门、部门名称和gpa);
//printf(“%s:%.1f\n”,部门名称,gpa);
_添加部门(部门名称,gpa);
//_print_dept();
bzero(部门名称,(国际)斯特伦(部门名称);
bzero(部门)(内部)strlen(部门);;
}
}//结束时
//_打印部门();
printf(“%d\n”,2);
关闭(儿童);
出口(0);
}//端叉
printf(“%d\n”,3);
关闭(子项);//父项不需要这个
}
printf(“%d\n”,4);
//_打印部门();
//_删除_全部();
返回0;
}
客户:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
#define PORT "3400"
#define NO_DEPARTMENTS 3
#define LINE_SIZE 7
#define HOST "localhost"
//Global variable containing respective departments file name extensions
char * filenames[] = {"DepartmentA.txt", "DepartmentB.txt", "DepartmentC.txt"};
char * department_names[] = {"DepartmentA", "DepartmentB", "DepartmentC"};
int main(void){
pid_t child_pid, wpid;
int status = 0;
for(int ii = 0; ii < NO_DEPARTMENTS; ii++){
if((child_pid = fork()) == 0){
int sockfd, rv;
char dept_ip[INET6_ADDRSTRLEN]; //Department IP address
unsigned int dept_port; //Department port
struct addrinfo hints, *servinfo, *p;
struct sockaddr_in my_addr;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if((rv = getaddrinfo(HOST, PORT, &hints, &servinfo)) != 0){
fprintf(stderr, "\ngetaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
//loop through all the results and connect to the first that we can find
for(p = servinfo; p != NULL; p = p->ai_next){
if((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1){
close(sockfd);
perror("client: socket");
continue;
}
if(connect(sockfd, p->ai_addr, p->ai_addrlen) == -1){
close(sockfd);
perror("client: connect");
continue;
}
break;
}
if(p == NULL){
fprintf(stderr, "client: failed to connect\n");
return 1;
}
//1) Upon startup of Phase 1
socklen_t len = sizeof(my_addr);
getsockname(sockfd, (struct sockaddr *)&my_addr, &len);
inet_ntop(AF_INET, &my_addr.sin_addr, dept_ip, sizeof(dept_ip));
dept_port = ntohs(my_addr.sin_port);
printf("<%s> has TCP port %d ", filenames[ii], dept_port);
printf("and IP address %s for Phase 1\n", dept_ip);
//2) Upon establishing a TCP connection to the admission office
printf("<%s> is now connected to the admission office\n", filenames[ii]);
//readfile and send contents to Addmissions office
struct Node * fileContent = NULL;
_readFile(&fileContent, filenames[ii]);
struct Node * fileIter = fileContent;
while(fileIter != NULL){
sleep(3);
send(sockfd, fileIter->dept, (int)strlen(fileIter->dept), 0);
fileIter = fileIter->next;
}
sleep(3);
char *ex = ":exit";
send(sockfd, ex, (int)strlen(ex), 0);
_freeFile(&fileContent);
freeaddrinfo(servinfo); // free up list structure
close(sockfd);
exit(0); //exit for fork
}
}
while ((wpid = wait(&status)) > 0);
return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义端口“3400”
#定义无需的部门3
#定义行大小为7
#定义主机“localhost”
//包含各个部门文件扩展名的全局变量
char*文件名[]={“DepartmentA.txt”、“DepartmentB.txt”、“DepartmentC.txt”};
char*部门名称[]={“部门A”、“部门B”、“部门C”};
内部主(空){
pid_t child_pid,wpid;
int status=0;
对于(int ii=0;ii<无部门;ii++){
if((child_pid=fork())==0){
int sockfd,rv;
char dept_ip[INET6_ADDRSTRLEN];//部门ip地址
未签名的int dept_port;//部门端口
结构addrinfo提示,*servinfo,*p;
我的地址中的结构sockaddr\u;
memset(&hints,0,sizeof(hints));
hits.ai_family=AF_unsec;
hits.ai_socktype=SOCK_流;
if((rv=getaddrinfo(主机、端口、提示和服务信息))!=0){
fprintf(标准格式,“\nGetAddressInfo:%s\n”,gai_strerror(rv));
返回1;
}
//循环浏览所有结果并连接到我们可以找到的第一个结果
for(p=servinfo;p!=NULL;p=p->ai_next){
if((sockfd=socket(p->ai_系列,p->ai_socktype,p->ai_协议))=-1){
关闭(sockfd);
perror(“客户端:套接字”);
持续
}
如果(连接(sockfd,p->ai_addr,p->ai_addrlen)=-1){
关闭(sockfd);
perror(“客户:连接”);
持续
}
打破
}
if(p==NULL){
fprintf(stderr,“客户端:连接失败\n”);
返回1;
}
//1) 第1阶段启动时
socklen\u t len=sizeof(我的地址);
getsockname(sockfd,(struct sockaddr*)和my_addr,&len);
inet_ntop(我的地址、我的地址、部门ip、大小(部门ip));
部门端口=ntohs(我的地址单端口);
printf(“具有TCP端口%d”,文件名[ii],部门端口);
printf(“第1阶段的IP地址%s”,部门IP);
//2) 建立与招生办公室的TCP连接后
printf(“现在已连接到入学办公室”,文件名[ii]);
//读取文件并将内容发送到Addmissions office
结构节点*fileContent=NULL;
_readFile(&fileContent,filename[ii]);
结构节点*fileIter=fileContent;
while(fileIter!=NULL){
睡眠(3);
发送(sockfd,文件管理器->部门,(内部)strlen(文件管理器->部门
if(counter > 0){
close(child); //parent doesn't need this
continue;
}else{
wait(&status);
printf("End of Phase 1 for the admission office\n");
break;
}