How to read connections at the same time using select? sockets/c - c

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int port = 3008;
int listenfd;
extern void makelistener();
int main(int argc, char **argv)
{
makelistener();
int clientfd, nready;
socklen_t len;
struct sockaddr_in q;
int i;
// initialize allset and add listenfd to the
// set of file descriptors passed into select
fd_set allset;
fd_set rset;
int maxfd;
FD_ZERO(&allset);
FD_SET(listenfd, &allset); // set of file descriptors
maxfd = listenfd;
int ret;
while (1)
{
// make a copy of the set before we pass it into select
rset = allset;
/*select will wait until an exceptional event occurs when tv is NULL*/
nready = select(maxfd + 1, &rset, NULL, NULL, NULL);
if (nready == 0) {
continue;
}
if (nready == -1) {
perror("select");
continue;
}
//FD_ISSET returns 1 when a new connection is attempted
if(FD_ISSET(listenfd, &rset)){
//printf("a new client is connecting\n");
len = sizeof(q); //accept connection of listenfd stream socket
if ((clientfd = accept(listenfd, (struct sockaddr *)&q, &len)) < 0) {
perror("accept");
exit(1);
}
FD_SET(clientfd, &allset);
if (clientfd > maxfd) {
maxfd = clientfd;
}
static char msg[] = "What is your name?\r\n";
write(clientfd, msg, sizeof msg - 1);
printf("connection from %s\n", inet_ntoa(q.sin_addr));
char buf[256];
ret = read(clientfd, buf, sizeof(buf));
buf[ret] = '\0';
printf("%s", buf);
}
}
}
void makelistener()
{
struct sockaddr_in r;
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
exit(1);
}
memset(&r, '\0', sizeof r);
r.sin_family = AF_INET;
r.sin_addr.s_addr = INADDR_ANY;
r.sin_port = htons(port);
if (bind(listenfd, (struct sockaddr *)&r, sizeof r)) {
perror("bind");
exit(1);
};
if (listen(listenfd, 5)) {
perror("listen");
exit(1);
}
}
above code is for the server and it does this
$ ./above.c
(does nothing but runs forever)
How to connect as a client:
$ nc 127.0.0.1 3000
What is your name?
(waiting for my input) so if I put bob, it would output it to the server
It works as intended. But I want it too work concurrently with multiple clients.
for example:
server
$ ./above.c
(does nothing but runs forever)
client1
$ nc 127.0.0.1 3000
What is your name?
client 2
$ nc 127.0.0.1 3000
What is your name? (Currently client2 wont show up until client1 is answered which is what I'm trying to fix)
How do I make it so the clients can run concurrently without waiting for the first client to finish? To explain the code a little bit, listener just binds and listens to a connection. Inside the while(1) is where select and calls are.

How do I make it so the clients can run concurrently without waiting for the first client to finish?
By paying attention to which sockets select() reports to you. You are asking select() to monitor multiple sockets for readability, but you are only checking if the listening socket is readable, you are not checking the client sockets. You need to keep track of the connected clients so you can enumerate them when needed.
Try something like this:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int port = 3008;
#define MAX_CLIENTS (FD_SETSIZE - 1)
int listenfd = -1;
extern void makelistener();
int main(int argc, char **argv)
{
int clientfd, nready;
socklen_t len;
struct sockaddr_in q;
int i, j, ret;
fd_set allset;
fd_set rset;
int clients[MAX_CLIENTS];
int num_clients = 0;
int maxfd;
char buf[256];
makelistener();
// initialize allset and add listenfd to the
// set of file descriptors passed into select
FD_ZERO(&allset);
FD_SET(listenfd, &allset);
maxfd = listenfd;
while (1)
{
// make a copy of the set before we pass it into select
FD_COPY(&allset, &rset);
// select will wait until an exceptional event occurs when tv is NULL
nready = select(maxfd + 1, &rset, NULL, NULL, NULL);
if (nready < 0) {
perror("select");
continue;
}
if (nready == 0) { // should never happen since no timeout was requested
continue;
}
//FD_ISSET returns 1 when a socket is readable
if (FD_ISSET(listenfd, &rset)) {
//printf("a new client is connecting\n");
len = sizeof(q); //accept connection of listenfd stream socket
if ((clientfd = accept(listenfd, (struct sockaddr *)&q, &len)) < 0) {
perror("accept");
exit(1);
}
printf("Client %d connected from %s\n", clientfd, inet_ntoa(q.sin_addr));
if (num_clients == MAX_CLIENTS) {
static char msg[] = "Max number of clients are already connected\r\n";
write(clientfd, msg, sizeof(msg)-1);
close(clientfd);
}
else {
static char msg[] = "What is your name?\r\n";
if (write(clientfd, msg, sizeof(msg)-1) < 0) {
close(clientfd);
}
else {
clients[num_clients++] = clientfd;
FD_SET(clientfd, &allset);
if (clientfd > maxfd) {
maxfd = clientfd;
}
}
}
}
for (i = 0; i < num_clients; ++i) {
clientfd = clients[i];
if (!FD_ISSET(clientfd, &rset)) {
continue;
}
ret = read(clientfd, buf, sizeof(buf));
if (ret <= 0) {
//printf("a client has disconnected\n");
close(clientfd);
FD_CLR(clientfd, &allset);
for (j = i + 1; j < num_clients; ++j) {
clients[j-1] = clients[j];
}
--num_clients;
if (clientfd == maxfd) {
maxfd = listenfd;
for (j = 0; j < num_clients; ++j) {
if (clients[j] > maxfd) {
maxfd = clients[j];
}
}
}
--i;
continue;
}
printf("Client %d: %.*s", clientfd, ret, buf);
}
}
return 0;
}
Note that poll() or epoll() would generally be a better choice to use than select().

How do I make it so the clients can run concurrently without waiting for the first client to finish?
every time that the call to accept() returns, start a thread pthread_create() to handle the actual communication with the client.
Note: creating/destroying a thread is very time consuming, so suggest learning about thread pools and how to use them.
When using threads, there is no call to select() (nor poll()) Rather the main function gets blocked on the call to accept() and when that function returns, pass the associated socket to a thread to handle
There are lots of example code for how a server should communicate with multiple clients on stackoverflow.com

Related

Why a TCP socket server written in C should not close client file descriptors in worker pthreads, but can close them in forked worker processes?

I wrote a simple TCP socket server in C, which creates a new child worker thread when it accepts a new connection request from a client and simply counts and sends numbers. If a client terminates, the corresponding child worker thread should also terminate, while the other threads should not.
If all clients are written in Python, when a client terminates, "Connection is reset by peer" is printed on the server, but everything else is fine, that is, other threads and clients are still working.
But if a client is written in C, when any clients and their corresponding child worker threads terminate, other threads also terminate, which is not expected. Why does it happen? I rewrote the server in Python, but this did not happen no matter what language the client is written in.
I then commented out close(*client_fd); and the issue is solved. I haven't got a clue, since it works fine in the server using fork().
The C code for server using pthread is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>
#define PORT 9000
#define CONNECTIONS 2
#define MAX_BUFFER_SIZE 1024
struct sockaddr_in socket_address;
socklen_t socket_address_size = sizeof(socket_address);
int server_fd;
void *handle_request(void *fd) {
int *client_fd = (int *) fd;
char buffer[MAX_BUFFER_SIZE] = {0};
for (int i = INT_MAX; send(*client_fd, buffer, strlen(buffer), 0) >= 0 && i >= 0; i--) {
printf("%d\r\n", i);
sprintf(buffer, "%d", i);
}
if (close(*client_fd) < 0) {
perror("close client_fd");
}
return NULL;
}
int main(int argc, char *argv[]) {
int option = 1;
char buffer[MAX_BUFFER_SIZE] = {0};
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket");
exit(EXIT_FAILURE);
}
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &option, sizeof(option))) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
socket_address.sin_family = AF_INET;
socket_address.sin_addr.s_addr = htonl(INADDR_ANY);
socket_address.sin_port = htons(PORT);
if (bind(server_fd, (struct sockaddr *) &socket_address, socket_address_size) < 0) {
perror("bind");
exit(EXIT_FAILURE);
}
if (listen(server_fd, CONNECTIONS) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
pthread_t threads[CONNECTIONS];
int client_fds[CONNECTIONS];
for (int i = 0; i < CONNECTIONS; i++) {
client_fds[i] = accept(server_fd, (struct sockaddr *) &socket_address, &socket_address_size);
if (client_fds[i] < 0) {
perror("accept");
exit(EXIT_FAILURE);
}
if (pthread_create(&threads[i], NULL, handle_request, &client_fds[i]) < 0) {
perror("pthread_create");
exit(EXIT_FAILURE);
}
}
for (int i = 0; i < CONNECTIONS; i++) {
if (pthread_join(threads[i], NULL) < 0) {
perror("pthread_join");
}
}
close(server_fd);
return EXIT_SUCCESS;
}
The C code for server using fork() is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#define PORT 9000
#define CONNECTIONS 2
#define MAX_BUFFER_SIZE 1024
int main(int argc, char *argv[]) {
struct sockaddr_in socket_address;
socklen_t socket_address_size = sizeof(socket_address);
int server_fd, client_fd, option = 1;
char buffer[MAX_BUFFER_SIZE] = {0};
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket");
exit(EXIT_FAILURE);
}
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &option, sizeof(option))) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
socket_address.sin_family = AF_INET;
socket_address.sin_addr.s_addr = htonl(INADDR_ANY);
socket_address.sin_port = htons(PORT);
if (bind(server_fd, (struct sockaddr *) &socket_address, socket_address_size) < 0) {
perror("bind");
exit(EXIT_FAILURE);
}
if (listen(server_fd, CONNECTIONS) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
pid_t pids[CONNECTIONS];
for (int i = 0; i < CONNECTIONS; i++) {
pids[i] = fork();
if (pids[i] < 0) {
perror("fork");
exit(EXIT_FAILURE);
} else if (pids[i] == 0) {
if ((client_fd = accept(server_fd, (struct sockaddr *) &socket_address, &socket_address_size)) < 0) {
perror("accept");
exit(EXIT_FAILURE);
}
for (int i = INT_MAX; send(client_fd, buffer, strlen(buffer), 0) >= 0 && i >= 0; i--) {
printf("%d\r\n", i);
sprintf(buffer, "%d", i);
}
close(client_fd);
return EXIT_SUCCESS;
}
}
for (int i = 0; i < CONNECTIONS; i++) {
int wstatus;
if (waitpid(0, &wstatus, WUNTRACED) < 0) {
perror("waitpid");
}
}
close(server_fd);
return EXIT_SUCCESS;
}
The C code for client is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define IP_ADDRESS "127.0.0.1"
#define PORT 9000
#define MAX_BUFFER_SIZE 1024
int main(int argc, char *argv[]) {
int socket_fd;
struct sockaddr_in socket_address;
socklen_t socket_address_size = sizeof(socket_address);
ssize_t message_len;
char buffer[MAX_BUFFER_SIZE] = {0};
if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket");
exit(EXIT_FAILURE);
}
socket_address.sin_family = AF_INET;
socket_address.sin_addr.s_addr = inet_addr(IP_ADDRESS);
socket_address.sin_port = htons(PORT);
if (connect(socket_fd, (struct sockaddr *) &socket_address, socket_address_size) < 0) {
perror("connect");
exit(EXIT_FAILURE);
}
while ((message_len = recv(socket_fd, buffer, MAX_BUFFER_SIZE, 0)) > 0) {
buffer[message_len] = '\0';
puts(buffer);
}
close(socket_fd);
return EXIT_SUCCESS;
}
The Python code for server is as follows:
import socket
import threading
HOST = ''
PORT = 9000
CONNECTIONS = 2
TRUNK_SIZE = 1024
def handle_request(connection):
with connection:
count = 0
while True:
state = connection.send(f'{count}\r\n'.encode('utf-8'))
if not state:
print(f"Connection closed from {address}.")
break
print(count)
count += 1
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR | socket.SO_REUSEPORT, 1)
s.bind((HOST, PORT))
s.listen(CONNECTIONS)
threads = []
for c in range(CONNECTIONS):
connection, address = s.accept()
print(f'Connected by {address}.')
thread = threading.Thread(target=handle_request, args=(connection,), daemon=True)
thread.start()
threads.append(thread)
for thread in threads:
thread.join()
The Python code for client is as follows:
import socket
HOST = '127.0.0.1'
PORT = 9000
TRUNK_SIZE = 1024
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
while True:
data = s.recv(TRUNK_SIZE).decode('utf-8')
if not data:
print("Connection closed.")
break
print(data)
If your whole process suddenly goes down while writing to a socket, then due to a SIGPIPE signal you received (indicated by the error EPIPE). The standard action of SIGPIPE is to terminate the process. Implement a signal handler which will catch SIGPIPE signals (and probably ignore or deal with it).
The message "Connection is reset by peer" is an indication of a caught SIGPIPE signal.

No response from recv when using nonblocking socket

I am trying to create a portscanner in c. If the port is open, I want to get a response from the server. When I use regular blocking sockets, this works fine. For example, I know that for a certain address on my network, if I check port 80, it will return the html page to me when I call recv. I have tested this, and it works correctly every time.
However, I want to use nonblocking sockets, because sometimes certain servers will not respond and will cause the program to hang. I was able to get the nonblocking sockets to (kindof) work (the code is currently commented out below). I could see which ports were open, which were closed, and which timed out, but I was not able to get a response from the server (even though I know it should send one). What am I doing wrong?
tl;dr: When using nonblocking sockets (vs blocking), recv doesn't return any data.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <fcntl.h>
#define MAX_LEN 100000
int main(int argc, char **argv)
{
int sock, test_sock;
struct sockaddr_in server_addr;
struct hostent *hp;
char buf[MAX_LEN];
int num_bytes;
int err_code;
int START_PORT = 1;
int END_PORT = 100;
fd_set fdset;
struct timeval tv;
int opts;
// resolve server name for its IP address, etc.
hp = gethostbyname(argv[1]);
if (NULL == hp) {
perror("gethostbyname");
exit(2);
}
//printf("Here1\n");
// build remote server addr/port
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
memcpy(&server_addr.sin_addr, hp->h_addr, hp->h_length);
//server_addr.sin_port = htons(atoi(argv[2]));
test_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
for(int i=START_PORT; i<=END_PORT; i++) {
printf("Here2\n");
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //created the tcp socket
//opts = fcntl(sock, F_SETFL, O_NONBLOCK);
printf("Here3\n");
if (sock < 0)
{
perror("Socket()\n");
exit(1);
}
server_addr.sin_port = htons(i);
// connect to server
printf("Here4\n");
err_code = connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr));
printf("Here5\n");
/* ... */
if (err_code < 0) {
printf("Port %d: connection refused\n", i);
//exit(3);
} else {
printf("Port %d:\n", i);
memset(buf, 0, MAX_LEN);
// Create message to send
char message[256];
strcpy(message, "GET / HTTP/1.0\r\nHost: ");
strcat(message, argv[1]);
strcat(message, "\r\n\r\n");
unsigned total_bytes_sent = 0;
num_bytes = send(sock, message, strlen(message), 0);
if (num_bytes < 0) {
perror("send");
exit(4);
}
unsigned total_bytes_received = 0;
while(1) {
num_bytes = recv(sock, buf+total_bytes_received, MAX_LEN, 0);
if(num_bytes <= 0){
break;
}
total_bytes_received += num_bytes;
}
// display received ack message
//printf("Port %d:\n", i);
fflush(stdout);
write(1, buf, total_bytes_received);
printf("\n");
printf("Done...\n");
}
close(sock);
}
// close sock to release resource
close(sock);
return 0;
}
SOLUTION
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <errno.h>
#include <fcntl.h>
#define MAX_LEN 100000
int main(int argc, char **argv)
{
int sock, sock_test;
struct sockaddr_in server_addr;
struct hostent *hp;
char buf[MAX_LEN];
int num_bytes;
int err_code;
int START_PORT = 1;
int END_PORT = 100;
int valid = 1;
fd_set fdset;
struct timeval tv;
// resolve server name for its IP address, etc.
hp = gethostbyname(argv[1]);
if (NULL == hp) {
perror("gethostbyname");
exit(2);
}
// build remote server addr/port
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
memcpy(&server_addr.sin_addr, hp->h_addr, hp->h_length);
for(int i=START_PORT; i<=END_PORT; i++) {
sock_test = socket(AF_INET, SOCK_STREAM, 0);
if (sock_test < 0)
{
perror("Socket()\n");
exit(1);
}
fcntl(sock_test, F_SETFL, O_NONBLOCK);
server_addr.sin_port = htons(i);
connect(sock_test, (struct sockaddr *)&server_addr, sizeof(server_addr));
FD_ZERO(&fdset);
FD_SET(sock_test, &fdset);
tv.tv_sec = 3;
tv.tv_usec = 0;
if (select(sock_test + 1, NULL, &fdset, NULL, &tv) == 1)
{
int so_error;
socklen_t len = sizeof so_error;
getsockopt(sock_test, SOL_SOCKET, SO_ERROR, &so_error, &len);
if (so_error == 0) {
printf("%s:%d is open\n", argv[1], i);
memset(buf, 0, MAX_LEN);
// Create message to send
char message[256];
strcpy(message, "GET / HTTP/1.0\r\nHost: ");
strcat(message, argv[1]);
strcat(message, "\r\n\r\n");
printf("Here6\n");
unsigned total_bytes_sent = 0;
num_bytes = send(sock_test, message, strlen(message), 0);
printf("Here7\n");
int retry = 3;
unsigned total_bytes_received = 0;
while(retry) {
num_bytes = recv(sock_test, buf+total_bytes_received, MAX_LEN, 0);
if (0 == num_bytes)
{
/* socket has been closed by peer */
break;
}
else if(-1 == num_bytes)
{
if ((EAGAIN == errno) || (EWOULDBLOCK == errno))
{
/* no data to be read on socket */
retry--;
/* wait one second */
sleep(1);
}
else
{
/* other error */
perror("recv");
break;
}
}
else
{
total_bytes_received += num_bytes;
}
}
// display received ack message
//printf("Port %d:\n", i);
fflush(stdout);
write(1, buf, total_bytes_received);
printf("\n");
printf("Done...\n");
}
else
{
//printf("%s:%d is closed\n", argv[1], i);
}
} else {
printf("timed out\n");
valid = 0; //set the boolean flag to false
}
close(sock_test);
}
// close sock to release resource
close(sock_test);
return 0;
}
As pointed in comments, in non-blocking mode, you have to handle cases when
server is not ready to send data.
For man recv(3)
Return Value
Upon successful completion, recv() shall return the length of the message in bytes. If no messages are available to be received and the peer has performed an orderly shutdown, recv() shall return 0. Otherwise, -1 shall be returned and errno set to indicate the error.
Errors
The recv() function shall fail if:
EAGAIN or EWOULDBLOCK
The socket's file descriptor is marked O_NONBLOCK and no data is waiting to be received; or MSG_OOB is set and no out-of-band data is available and either the socket's file descriptor is marked O_NONBLOCK or the socket does not support blocking to await out-of-band data.
Since your client may try to read before the server send something, you must
adapt your code to wait:
/* maximum number of retry, one second per retry */
int retry = 10;
unsigned total_bytes_received = 0;
while(retry) {
num_bytes = recv(sock, buf+total_bytes_received, MAX_LEN, 0);
if (0 == num_bytes)
{
/* socket has been closed by peer */
break;
}
else if(-1 == num_bytes)
{
if ((EAGAIN == errno) || (EWOULDBLOCK == errno))
{
/* no data to be read on socket */
retry--;
/* wait one second */
sleep(1);
}
else
{
/* other error */
perror("recv");
break;
}
}
else
{
total_bytes_received += num_bytes;
}
}

TCP server/client how to keep connections alive?

I wrote a simple TCP echo server to handle multiple clients. It uses select() to get multiple connections.
Server Code:
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
int create_listener(uint16_t port) {
int listen_fd;
struct sockaddr_in name;
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_fd < 0) {
perror ("socket");
exit(EXIT_FAILURE);
}
bzero(&name, sizeof(name));
name.sin_family = AF_INET;
name.sin_addr.s_addr = htonl(INADDR_ANY);
name.sin_port = htons(port);
if (bind(listen_fd, (struct sockaddr *) &name, sizeof(name)) < 0) {
perror ("bind");
exit(EXIT_FAILURE);
}
return listen_fd;
}
int read_from_client(int fd) {
char buffer[100];
int nbytes;
nbytes = read(fd, buffer, 100);
if (nbytes < 0) {
perror("read");
exit(EXIT_FAILURE);
}
else if (nbytes == 0) {
return -1;
}
else {
fprintf(stderr, "Server: got message: %s\n", buffer);
write(fd, buffer, strlen(buffer) + 1);
return 0;
}
}
int main(int argc, char *argv[]) {
int listen_fd;
uint16_t port = 22000;
fd_set active_fd_set, read_fd_set;
int i;
struct sockaddr_in servaddr;
/* Create the socket and set it up to accept connections. */
listen_fd = create_listener(port);
if (listen(listen_fd, 10) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
/* Initialize the set of active sockets. */
FD_ZERO(&active_fd_set);
FD_SET(listen_fd, &active_fd_set);
while (1) {
/* Block until input arrives on one or more active sockets. */
read_fd_set = active_fd_set;
if (select(FD_SETSIZE, &read_fd_set, NULL, NULL, 0) < 0) {
perror("select");
exit(EXIT_FAILURE);
}
/* Service all the sockets with input pending. */
for (i = 0; i < FD_SETSIZE; ++i) {
if (FD_ISSET(i, &read_fd_set)) {
if (i == listen_fd) {
/* Connection request on original socket. */
int new_fd;
new_fd = accept(listen_fd, (struct sockaddr *) NULL, NULL);
if (new_fd < 0) {
perror ("accept");
exit(EXIT_FAILURE);
}
FD_SET(new_fd, &active_fd_set);
}
else {
/* Data arriving on an already-connected socket. */
if (read_from_client(i) < 0) {
close(i);
FD_CLR(i, &active_fd_set);
}
}
}
}
}
return 0;
}
Client code:
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int sockfd, n;
char sendline[100];
char recvline[100];
struct sockaddr_in servaddr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(22000);
inet_pton(AF_INET, "127.0.0.1", &(servaddr.sin_addr));
connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
while (1) {
bzero(sendline, 100);
bzero(recvline, 100);
fgets(sendline, 100, stdin);
write(sockfd, sendline, strlen(sendline) + 1);
read(sockfd, recvline, 100);
printf("%s", recvline);
}
return 0;
}
The problem is when I run server in one terminal and run two clients in another two terminals. If I use Ctrl+C to terminate one client, the server automatically terminates. I'm wondering why the server acts this way. What I'm expecting is the server runs forever. When client 1 terminates, server should still has a live connection with client 2.
Looks like you're hitting the exit in read_from_client. In general, in a server that serves multiple clients, you probably don't want to exit when you have a failure with one of the client connections.

Why my server and client appear TIME_WAIT at the same time?

I met a strange problem when I test my server and client.
The server and client appear TIME_WAIT at the same time!
Here is my server code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h> //bzero
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#define LISTEN_QUEUE 20
#define MAX_LINE 1024
#define MAXN 16384
int parse(char *buf)
{
int num;
sscanf(buf, "%d", &num);
return num;
}
int main()
{
int listenfd, connfd, r, n;
pid_t childpid;
socklen_t chilen;
struct sockaddr_in chiaddr, servaddr;
char buf[MAX_LINE];
char content[MAXN];
listenfd = socket(AF_INET, SOCK_STREAM, 0);
if(listenfd < 0)
printf("listen socket get error\n"), exit(-1);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(9999);
r = bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
if(r < 0)
printf("bind socket error\n"), exit(-1);
r = listen(listenfd, LISTEN_QUEUE);
memset(content, 'A', MAXN);
while(1)
{
chilen = sizeof(chiaddr);
connfd = accept(listenfd, (struct sockaddr *)&chiaddr, &chilen);
memset(buf, 0, MAX_LINE);
r = read(connfd, buf, MAX_LINE);
n = parse(buf);
write(connfd, content, n);
close(connfd);
}
}
And here is my client code:
#include <unp.h>
#define MAXN 16384
static int readn(int fd, char *buf, int nbytes)
{
int nread, ntoread, n;
#ifdef __DEBUG__
char temp[1024];
#endif /* __DEBUG__ */
nread = 0;
ntoread = nbytes;
while(nread < nbytes)
{
n = read(fd, buf, ntoread);
if(n < 0)
printf("read nbytes error\n"), exit (-1);
else if(n == 0)
break;
else
{
#ifdef __DEBUG__
memcpy(temp, buf, n);
temp[n] = 0;
printf("%s\n", temp);
#endif /* _DEBUG__ */
buf += n;
nread += n;
ntoread = nbytes - nread;
}
}
return nread;
}
static int Tcp_connect(char *host, char *port)
{
struct hostent *h;
char str[16];
struct sockaddr_in addr;
h = gethostbyname(host);
addr.sin_family = h->h_addrtype;
addr.sin_port = htons(atoi(port));
addr.sin_addr = *(struct in_addr *)(h->h_addr);
#ifdef __DEBUG__
if(h->h_addrtype == AF_INET)
printf("AF_INET\n");
printf("server ip is :%s\n", inet_ntoa(addr.sin_addr));
#endif /* __DEBUG__ */
int fd = socket(h->h_addrtype, SOCK_STREAM, 0);
if(fd < 0)
printf("socket get failed\n"), exit(-1);
#ifdef __DEBUG__
printf("socket get success\n");
#endif /* __DEBUG__ */
if(connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
printf("connect failed\n"), exit(-1);
#ifdef __DEBUG__
printf("connected success\n");
#endif /* __DEBUG__ */
return fd;
}
int main(char argc, char *argv[])
{
int i, j, fd, nchilds, nloops, nbytes;
pid_t pid;
ssize_t n, nread;
char request[MAX_LINE], reply[MAXN];
if(argc != 6)
printf("usage : client <IP addr> <port> <#children>
<#loops/child> <#bytes/request>"),
exit(-1);
nchilds = atoi(argv[3]);
nloops = atoi(argv[4]);
nbytes = atoi(argv[5]);
snprintf(request, sizeof(request), "%d\n", nbytes);
for(i = 0; i < nchilds; i++)
{
if((pid = fork()) == 0) //son
{
nread = 0;
for(j = 0; j < nloops; j++)
{
// printf("begin connect\n");
fd = Tcp_connect(argv[1], argv[2]);
write(fd, request, strlen(request));
if((n = readn(fd, reply, nbytes)) != nbytes)
printf("server return %d bytes\n", (int)n), exit(-1);
else
nread += n;
close(fd);
}
printf("child %d done, read total %d bytes\n", i, (int)nread);
exit(0);
}
}
while(wait(NULL) > 0) ;
if(errno != ECHILD)
printf("wait error\n"), exit(-1);
}
I run server and client on my machine.
And the client cmd is
./client 127.0.0.1 9999 5 100 4000
and then I run
netstat -a | grep 9999 > log
when I run
grep -c TIME_WAIT log
the result is 501, but according to book, the result should be 500.
I open the log, then I find server and client in TIME_WAIT at the same time on one connection
tcp 0 0 localhost:54915 localhost:9999 TIME_WAIT
tcp 0 0 localhost:9999 localhost:54915 TIME_WAIT
It is so strange, I don't know why
You are establishing and closing connection between client and server in loop - client connects to server, sends some data, receives response from server and then closes the connection. Similarly the server also disconnects after this exchange. You are observing TIME_WAIT state as you are closing connections between client and server.
The TIME_WAIT state is a normal TCP connection state, as the TCP stack does not immediately wipe out the TCBs after FIN exchange. The TIME_WAIT state represents waiting for enough time to pass to be sure the remote TCP received the acknowledgment of its connection termination request. Please refer to TCP RFC 793 for more details on TCP state machine.
If you do a grep on port 9999, you will notice connection in ESTABLISHED state while your client and server are running.
Possibly you can avoid establishing and closing TCP connection in loop, that is, change your server and client programs to establish connection and then enter the loop for exchanging data.

c socket prog - select() problems

I'm new to network programming. I have to write a simple client/server program in C. The server will listen for a connection and the client will connect to the server, send a message, and receive an echo back from the client. We have to update this using select() to handle connections to multiple clients at the same time from the server process. I tried to implement select() on the client side like instructed,but I think I'm having an infinite loop on the client side in if(FD_ISSET(clientSockfd, &readfds)) part.
//client1.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <resolv.h>
#include <arpa/inet.h>
const int BUF_SIZE = 512;
int main(int argc, char *argv[]) {
char buf[BUF_SIZE], buf2[BUF_SIZE];
char *msg;
struct sockaddr_in serverInfo;
int clientSockfd, errorCheck, readVal, numfd;
struct hostent *hostName;
fd_set readfds;
//make sure user entered correct arguments when starting client
if(argc != 3)
{
printf("error: must enter 'programName portNumber hostname'\n");
exit(errno);
}
//create socket and error check socket() call
clientSockfd=socket(AF_INET, SOCK_STREAM, 0);
if (clientSockfd == -1)
{
perror("error creating socket");
exit(errno);
}
//assign sockaddr_in info for RemoteAddr
bzero(&serverInfo, sizeof(serverInfo));
serverInfo.sin_family=AF_INET;
hostName=gethostbyname(argv[2]);
if(hostName == NULL)
{
herror("Error when calling gethostbyname()");
exit(errno);
}
memcpy((unsigned char *) &serverInfo.sin_addr, (unsigned char *)hostName->h_addr, hostName->h_length); //copy IP address to be used
serverInfo.sin_port=htons(atoi(argv[1])); //port number to be used, given in command line, must be converted to network byte order
//connect to server side
if(connect(clientSockfd, (struct sockaddr *)&serverInfo, sizeof(serverInfo)) == -1)
{
perror("error when connecting to server");
exit(errno);
}
while(1)
{
FD_ZERO(&readfds); //zero out set
FD_SET(fileno(stdin), &readfds);
FD_SET(clientSockfd, &readfds);
int maxfd = fileno(stdin);
if(maxfd < clientSockfd) maxfd = clientSockfd;
numfd = select(maxfd, &readfds, 0, 0, 0); //call select()
if(numfd > 0)
{
if(FD_ISSET(clientSockfd, &readfds))
{
//make sure buf is empty so it doesnt print extra chars
bzero(buf2, BUF_SIZE);
read(clientSockfd, buf2, BUF_SIZE);
}
if(FD_ISSET(fileno(stdin), &readfds))
{
bzero(buf, BUF_SIZE);
fgets(buf, BUF_SIZE-1, stdin);
printf("echo from server: %s\n", buf);
errorCheck = write(clientSockfd, buf, strlen(buf)+1);
if(errorCheck == -1)
{
perror("error writing");
}
}
}
else if(numfd == 0)
{
perror("Error using select()\n");
exit(0);
}
else
printf("no data\n");
}
//close connection to server
errorCheck = close(clientSockfd);
if(errorCheck == -1)
{
perror("Error closing connection.");
exit(errno);
}
return 0;
}
here is the server..
//server.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <resolv.h>
#include <arpa/inet.h>
#include <errno.h>
const int ASSIGNED_PORT = 17000;
const int BUF_SIZE = 512;
int main() {
int serverfd, clientfd;
struct sockaddr_in serverSock; //NOTE: a pointer to sockaddr_in can be cast to a pointer to
// a struct sockaddr - useful for connect()
char buf[BUF_SIZE];
int errorCheck, msgLength;
//create socket with error checking (-1 ret on error)
serverfd = socket(AF_INET, SOCK_STREAM, 0);
if(serverfd < 0 )
{
perror("socket failed.");
exit(errno);
}
//assign sockaddr_in info for server
bzero(&serverSock, sizeof(serverSock)); //set to all 0's
serverSock.sin_family = AF_INET;
serverSock.sin_addr.s_addr = htonl(INADDR_ANY);
serverSock.sin_port = htons(ASSIGNED_PORT);
//bind a name to the socket with error checking (0 ret on success)
errorCheck = bind(serverfd, (struct sockaddr*)&serverSock, sizeof(serverSock));
if(errorCheck < 0 )
{
perror("bind failed.");
exit(errno);
}
//listen for connections with error checking (0 ret on success)
errorCheck = listen(serverfd, 10);
if(errorCheck < 0 )
{
perror("listen failed.");
exit(errno);
}
printf("Listening for connections. Enter CNTRL-c to kill server.\n");
//create infinite loop to accept, read, write, and close connections with error hecking
while(1)
{
//accept the connection from the client
clientfd = accept(serverfd, 0, 0);
if(clientfd == -1)
{
perror("error accepting connection.");
exit(errno);
}
//read data from the client
bzero(buf, BUF_SIZE);
msgLength = read(clientfd, buf, BUF_SIZE-1);
if(msgLength == -1)
{
perror("error reading from client");
close(clientfd);
close(serverfd);
exit(errno);
}
if(buf[0] '\0')
{
printf("connection closing");
exit(0);
}
//print what the client sent
printf("Message from client: %s\n", buf);
//echo back what the client sent
errorCheck = write(clientfd, buf, strlen(buf)+1);
if(errorCheck == -1 )
{
perror("error writing to client");
exit(errno);
}
//close the connection
errorCheck = close(clientfd);
if(errorCheck == -1)
{
perror("error closing connection");
exit(errno);
}
}
errorCheck = close(serverfd);
if(errorCheck==-1)
{
perror("error closing server, exiting program now");
sleep(6);
exit(errno);
}
return 0;
}
I think the problem (or at least, a problem) in your client-side code is that you are passing the magic number 32 to select(). That's incorrect. What you should be passing is the maximum of all of the socket numbers, plus one. For example, something like this:
int maxfd = fileno(stdin);
if (maxfd < clientSockFD) maxfd = clientSockFD;
// further maximizations for other sockets would go here, if you had any other sockets...
numfd = select(maxfd+1, &readfds, 0, 0, 0);
You need to use select() on the server side to handle multiple clients, not on the client side.

Resources