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

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.

Related

send() function is never called in server C

I have a server program here that checks the input sent from the client and returns a message back to the client wether the password is right or wrong .
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Practical.h"
#include <unistd.h>
#include <sys/stat.h>
#define BUFSIZE 200
int main(int argc, char* argv[])
{
int numBytes = 0;
int MAXPENDING = 1;
char recvbuffer[BUFSIZE], sendbuffer[BUFSIZE];
char inp_user[BUFSIZE];
char inp_pass[BUFSIZE];
char pass[BUFSIZE] = "pass";
char user[BUFSIZE] = "admin";
int attemptsLeft = 3;
if (argc != 2)
DieWithUserMessage("Parameter(s)", "<Server Port>");
in_port_t servPort = atoi(argv[1]);
int servSock;
if ((servSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
DieWithSystemMessage("socket() failed");
struct sockaddr_in servAddr;
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
servAddr.sin_port = htons(servPort);
if (bind(servSock, (struct sockaddr*) &servAddr, sizeof(servAddr)) < 0)
DieWithSystemMessage("bind() failed");
//accept incoming connection requests to the server socket
//MAXPENDING is the maximum number of connections
//that should be queued for this socket
if (listen(servSock, MAXPENDING) < 0)
DieWithSystemMessage("listen() failed");
for (;;)
{
//declare client address structure
struct sockaddr_in clntAddr;
socklen_t clntAddrLen = sizeof(clntAddr);
//return new file descriptor referring
//to the client socket , all read/write operations will be
//performed on this socket
int clntSock = accept(servSock, (struct sockaddr *) &clntAddr, &clntAddrLen);
//check if the client socket has not been created
if (clntSock < 0)
DieWithSystemMessage("accept() failed");
//retrieve the data sent by the client
while ((numBytes = recv(clntSock, recvbuffer, (BUFSIZE-1), 0)) > 0) {
recvbuffer[numBytes] = '\0';
fputs(recvbuffer, stdout);
// if(strstr(recvbuffer, "\r\n\r\n") > 0)
// break;
}
//check if data has not been received from the client
if (numBytes < 0)
DieWithSystemMessage("recv() failed");
//read username and password into the server's buffers
sscanf(recvbuffer, "%s %s", inp_user, inp_pass);
//check if the entered username and pasword is correct
if( (strcmp(user, inp_user) == 0)
&&
(strcmp(pass, inp_pass) == 0)
)
{
snprintf(sendbuffer, sizeof(sendbuffer), "%s", "PROCEED\r\n");
}
else //the credentials entered were incorrect
{
attemptsLeft--;
//check if user has no attempts left
if(attemptsLeft == 0) {
snprintf(sendbuffer, sizeof(sendbuffer), "%s", "DENIED\r\n" );
} else {
snprintf(sendbuffer, sizeof(sendbuffer), "%s", "NONO\r\n");
// "You have %d attempt(s) left", attemptsLeft);
}
}
printf("The send message contains %s \n\n", sendbuffer);
printf("brefore sending\n");
ssize_t numBytesSent = send(clntSock, sendbuffer, strlen(sendbuffer), 0);
printf("after sending\n");
if (numBytesSent < 0)
DieWithSystemMessage("send() failed");
printf("NOBYTES: %d", numBytes);
close(clntSock);
}
}
The message contains prints successfully meaning a message is created for the user however the send() function is never called and the client never receives this message. Anyone know why this would happen?

SCTP client and server meets error when reading message sent by the other

I'm implementing a simple SCTP client and server with Linux SCTP socket API. Client and server both use one-to-one socket style. After connecting to server, the client sends a hello message to server and the server responds back with its hello message. Here' the code for server and client:
server.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
#include "common.h"
int main(int argc, char *argv[])
{
int srvr_sock;
struct sockaddr_in srv_addr;
struct sockaddr_in clnt_addr;
struct sctp_sndrcvinfo sndrcvinfo;
struct sctp_event_subscribe event;
socklen_t addr_sz;
char snd_buf[] = "Hello from server";
char rcv_buf[1024] = {0};
int new_fd;
int flags;
int rd_sz;
int ret;
/* One-to-one style */
/* Create socket */
srvr_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP);
if (srvr_sock < 0)
{
perror("Open srvr_sock");
exit(EXIT_FAILURE);
}
/* Bind to server address */
memset(&srv_addr, 0, sizeof(srv_addr));
srv_addr.sin_family = AF_INET;
srv_addr.sin_port = htons(SERVER_PORT_NUM);
srv_addr.sin_addr.s_addr = inet_addr(SERVER_IP_ADDR_1);
ret = bind(srvr_sock, (struct sockaddr *) &srv_addr, sizeof(srv_addr));
if (ret < 0)
{
perror("Bind srvr_sock");
exit(EXIT_FAILURE);
}
/* Enable all events */
event.sctp_data_io_event = 1;
event.sctp_association_event = 1;
event.sctp_address_event = 1;
event.sctp_send_failure_event = 1;
event.sctp_peer_error_event = 1;
event.sctp_shutdown_event = 1;
event.sctp_partial_delivery_event = 1;
event.sctp_adaptation_layer_event = 1;
if (setsockopt(srvr_sock, IPPROTO_SCTP, SCTP_EVENTS, &event,
sizeof(event)) != 0)
{
perror("setsockopt failed");
exit(EXIT_FAILURE);
}
/* Listen */
ret = listen(srvr_sock, 5);
if (ret < 0)
{
perror("Listen on srvr_sock");
exit(EXIT_FAILURE);
}
/* Server loop */
while (1)
{
printf("Waiting for new connection...\n");
new_fd = accept(srvr_sock, (struct sockaddr *)&clnt_addr, &addr_sz);
if (new_fd < 0)
{
perror("Failed to accept client connection");
continue;
}
memset(rcv_buf, 0, sizeof(rcv_buf));
rd_sz = sctp_recvmsg(new_fd, (void *)rcv_buf, sizeof(rcv_buf),
(struct sockaddr *) NULL,
0,
&sndrcvinfo,
&flags);
if (rd_sz <= 0)
{
continue;
}
if (flags & MSG_NOTIFICATION)
{
printf("Notification received. rd_sz=%d\n", rd_sz);
}
printf("New client connected\n");
printf("Received %d bytes from client: %s\n", rd_sz, rcv_buf);
/* Send hello to client */
ret = sctp_sendmsg(new_fd, /* sd */
(void *) snd_buf, /* msg */
strlen(snd_buf), /* len */
NULL, /* to */
0, /* to len */
0, /* ppid */
0, /* flags */
STREAM_ID_1, /* stream_no */
0, /* TTL */
0 /* context */);
if (ret < 0)
{
perror("Error when send data to client");
}
else
{
printf("Send %d bytes to client\n", ret);
}
if (close(new_fd) < 0)
{
perror("Close socket failed");
}
}
close(srvr_sock);
return 0;
}
client.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
#include "common.h"
int main(int argc, char *argv[])
{
int conn_fd;
struct sockaddr_in srvr_addr;
struct sctp_sndrcvinfo sndrcvinfo;
socklen_t addr_sz = sizeof(struct sockaddr_in);
int flags;
char rcv_buf[1024] = {0};
char snd_buf[] = "Hello from client";
int rcv_cnt;
int ret;
/* One-to-one style */
/* Create socket */
conn_fd = socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP);
if (conn_fd < 0)
{
perror("Create socket conn_fd");
exit(EXIT_FAILURE);
}
/* Specify the peer endpoint to which we'll connect */
memset(&srvr_addr, 0, sizeof(srvr_addr));
srvr_addr.sin_family = AF_INET;
srvr_addr.sin_port = htons(SERVER_PORT_NUM);
srvr_addr.sin_addr.s_addr = inet_addr(SERVER_IP_ADDR_1);
/* Connect */
ret = connect(conn_fd, (struct sockaddr *)&srvr_addr, sizeof(srvr_addr));
if (ret < 0)
{
perror("Connect failed");
exit(EXIT_FAILURE);
}
printf("Connected to server\n");
/* Send hello to server */
ret = sctp_sendmsg(conn_fd, (void *)snd_buf, strlen(snd_buf),
(struct sockaddr *) &srvr_addr, sizeof(srvr_addr), 0,
0, STREAM_ID_1, 0, 0);
if (ret < 0)
{
perror("Send to server failed");
close(conn_fd);
exit(EXIT_FAILURE);
}
else
{
printf("Send %d bytes to server\n", ret);
}
/* Read message from server */
rcv_cnt = sctp_recvmsg(conn_fd, (void *)rcv_buf, sizeof(rcv_buf),
(struct sockaddr *) &srvr_addr, &addr_sz,
&sndrcvinfo, &flags);
if (rcv_cnt <= 0)
{
printf("Socket error or EOF\n");
}
else if (flags & MSG_NOTIFICATION)
{
printf("Notification received. rcv_cnt=%d\n", rcv_cnt);
}
else
{
printf("Received %d bytes from server: %s\n", rcv_cnt, rcv_buf);
}
/* close socket */
close(conn_fd);
return 0;
}
common.h
#define SERVER_PORT_NUM 16789
#define SERVER_IP_ADDR_1 "192.168.56.102"
#define STREAM_ID_1 1
Client and server are running on 2 Debian VMs in the same subnet, client's IP is 192.168.56.101, server's IP is 192.168.56.102.
When I start the server and then run the client, most of the time the client fails with following output:
./client
Connected to server
Send to server failed: Cannot assign requested address
However the server shows that it has read data sent from client and has responded with server hello message:
./server
Waiting for new connection...
Notification received. rd_sz=20
New client connected
Received 20 bytes from client: ▒
Send 17 bytes to client
Waiting for new connection...
Also the data received from client is corrupted in this case.
I tried to run the client many times and sometimes it succeeds:
$ ./client
Connected to server
Send 17 bytes to server
Received 17 bytes from server: Hello from server
The server still shows same log messages in this case.
Why would the client fail most of the time while only succeed a few times? The result seems to be unpredictable to me. Also why the data read by server is corrupted in server's output?
Try to bind also client socket.
In client.c between socket create and before connect put:
cli_addr.sin_family = AF_INET;
cli_addr.sin_port = 0;
cli_addr.sin_addr.s_addr = inet_addr(INADDR_ANY); /* or inet_addr("192.168.56.101");
for multiple ip addresses or network cards */
ret = bind(conn_fd, (struct sockaddr *) &cli_addr, sizeof(cli_addr));
if (ret < 0)
{
perror("Bind client_sock");
exit(EXIT_FAILURE);
}

How to read connections at the same time using select? sockets/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

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.

Resources