使用fork创建的客户端程序读取多个文件并创建单独的套接字。然后,每个套接字将其读取的文件中的消息发送到服务器,该服务器使用fork处理多个客户端。但是,服务器永远不会退出accept循环-因此,即使关闭了客户端上的所有套接字,它也不会终止。
服务器:
#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;
}
客户端:
#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;
}
答案 0 :(得分:0)
解决了!我必须使要接受的队列(BACKLOG)与部门数相同,在这种情况下为3。然后,我将计数器初始化为队列的大小,并在每次执行接受时将其递减。一旦计数器为零,我就让父进程等待所有子进程,然后手动中断accept循环。
RichText(
text: TextSpan(
text: 'Hello ',
style: TextStyle(color: Colors.black, fontWeight: FontWeight.w900)),
children: <TextSpan>[
TextSpan(text: 'bold', style: TextStyle(fontWeight: FontWeight.bold)),
TextSpan(text: ' world!'),
],
),
)