-
Notifications
You must be signed in to change notification settings - Fork 0
/
select_server.c
158 lines (140 loc) · 3.96 KB
/
select_server.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#define PORT "3490" // the port users will be connecting to
#define BACKLOG 10 // how many pending connections queue will hold
#define MAXDATASIZE 100 // max number of bytes we can get at once
void sigchld_handler(int s)
{
while(waitpid(-1, NULL, WNOHANG) > 0);
}
int main(void)
{
int sockfd, new_fd; // listen on sock_fd, new connection on new_fd
struct addrinfo hints, *servinfo, *p;
struct sockaddr_in their_addr; // connector's address information
socklen_t sin_size;
int yes=1;
char s[INET6_ADDRSTRLEN];
int rv;
char buf[MAXDATASIZE];
int numbytes;
struct sigaction sa;
pid_t pid;
int err;
int i;
int fdmax; // maximum file descriptor number
fd_set master; // master file descriptor list
fd_set read_fds; // temp file descriptor list for select()
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // use my IP
if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through 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;
}
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
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 2;
}
freeaddrinfo(servinfo); // all done with this structure
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(1);
}
printf("server: waiting for connections...\n");
sin_size = sizeof their_addr;
sa.sa_handler = sigchld_handler; // reap all dead processes
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction");
exit(1);
}
while(1){
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
if (new_fd == -1) {
// perror("accept");
return;
}
inet_ntop(their_addr.sin_family,(struct sockaddr *)&their_addr.sin_addr,s, sizeof s);
printf("server: got connection from %s port: %d\n", s,their_addr.sin_port);
pid = fork();
if (!pid) { // this is the child process
close(sockfd); // child doesn't need the listener
while(1){
FD_ZERO(&master); // clear the master and temp sets
FD_ZERO(&read_fds);
FD_SET(new_fd, &master); // add to master set
FD_SET(0, &master); // add to master set
fdmax = new_fd;
read_fds = master; // copy it
restart_select:
if ((err = select(fdmax+1, &read_fds, NULL, NULL, NULL)) == -1) {
if(err == EINTR){
goto restart_select;
}
// perror("select");
exit(4);
}
for(i = 0; i <= fdmax; i++) {
if (FD_ISSET(i, &read_fds)) { // catched
if(i == new_fd){ // data received
memset(buf,0,MAXDATASIZE);
if ((numbytes = recv(new_fd, buf, 256, 0)) == -1) {
perror("recv");
exit(1);
}else if (numbytes == 0) {
// connection closed
printf("Client socket %s hung up\n",s );
close(new_fd); // parent doesn't need this
return 0;
}else{
printf("RCV [%s] :%s",s,buf);
}
}else if(i == 0){
memset(buf,0,MAXDATASIZE);
fgets(buf,MAXDATASIZE,stdin);
printf("SND: %s\n", buf);
if (send(new_fd, buf,strlen(buf) , 0) == -1) {
perror("send");
}
// printf("send data: %s",buf);
}
}
}
}
}
// printf("Client socket %s closed\n",s );
close(new_fd); // parent doesn't need this
}
close(sockfd); // listen socket
return 0;
}