recvfrom() hanging after receiving some messages? - c

I am writing a simple multi-threaded client-server UDP program in C where I send multiple messages at once to the server, and wait for the replies in my receive thread. I'm doing this in order to test the time packets are sent and received.
I have tested locally with my server with 10 packets, and I am correctly receiving all 10 packets, at which point my program terminates.
However, when I test my client with a remote server, my program hangs after I receive about 6 packets. I know the program is hanging on the recvfrom() call, but I don't know why.
I have tried changing the parameters in the call and putting the call in the while loop itself, but to no avail.
Here is my client code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
#include <sys/time.h>
#define SERVER_IP "127.0.0.1"
#define PORT 7851
#define DATA_SIZE 99
#define NUM_MSGS 10
// function declaration for connection handler
void *connection_handler(void *);
struct timeval times[NUM_MSGS][2];
struct sockaddr_in serverAddress;
int main() {
int socketFd;
char buf[DATA_SIZE];
//struct sockaddr_in serverAddress;
char msg[DATA_SIZE];
int size, numSent;
time_t timeSent;
pthread_t threadId;
// Create the socket
if ((socketFd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("Socket creation failure");
exit(-1);
}
// Initialize server information
serverAddress.sin_family = AF_INET;
serverAddress.sin_addr.s_addr = inet_addr(SERVER_IP);
serverAddress.sin_port = htons(PORT);
// Print server information
printf("IP address of server is: %s\n", inet_ntoa(serverAddress.sin_addr));
printf("Server port is: %d\n", (int) ntohs(serverAddress.sin_port));
// Create new thread to handle received messages from server
if (pthread_create(&threadId, NULL, connection_handler, (void *)&socketFd) < 0) {
perror("Thread creation failure");
exit(-1);
}
numSent = 0;
int i, j, n;
for (i = 0; i < NUM_MSGS; i++) {
// Get current time and create message
gettimeofday(&times[i][0], NULL);
n = snprintf(msg, DATA_SIZE, "%d", numSent);
msg[n] = '\0';
if (n < 0 || n > DATA_SIZE) {
perror("Message creation failure");
}
// Send msg to server
size = sendto(socketFd, (char *)msg, strlen(msg), 0, (struct sockaddr *) &serverAddress, sizeof(serverAddress));
// Check for sendto error
if (size == -1) {
perror("sendto failure");
exit(-1);
}
printf("Client message %d sent.\n", numSent);
numSent++;
}
// Wait for straggler replies
sleep(2);
pthread_join(threadId, NULL);
//print out times
for (i = 0; i < NUM_MSGS; i++){
for (j = 0; j < 2; j++){
printf("[%d][%d] = [%ld.%06ld]\n", i, j, (long int)(times[i][j].tv_sec), (long int)(times[i][j].tv_usec));
}
}
close(socketFd);
return 0;
}
// Connection handler function for new thread created to receive server replies
void *connection_handler(void *newSocketPtr) {
// cast newSocketPtr to integer ptr then dereference to get the socketFd
int socketFd = *(int *)newSocketPtr;
char buf[DATA_SIZE];
int addrLen, size;
int numReceived = 0;
time_t timeSent, timeReceived, diff, totalTime, avgRTT;
addrLen = sizeof(serverAddress);
while ((size = recvfrom(socketFd, (char *)buf, DATA_SIZE, 0, (struct sockaddr *) &serverAddress, &addrLen))!= -1){ // What about when packets get dropped???
printf("Expecting packet %d\n", numReceived+1);
// Check for recvfrom error
if (size == -1){
perror("recvfrom failure");
exit(-1);
}
buf[size] = '\0';
// Get current time
gettimeofday(&times[atoi(buf)][1], NULL);
printf("Message received from server: %s\n", buf);
if (numReceived == NUM_MSGS - 1)break;
numReceived++;
printf("num received is %d\n", numReceived);
}
close(socketFd);
pthread_exit(NULL);
}

[...] tested locally with my server with 10 packets [...] test my client with a remote server, my program hangs after I receive about 6 packets.
UDP simply does not guarantee that packets will be delivered. Your remote server was to slow and missed four packets.

Related

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);
}

C Programming multiple threads on XUbuntu

I'm trying make the program run multiple threads to it connects to different ports. I successfully made it work on a single thread but not multiple.
Below I have posted the code of what I'm using on XUbuntu.
server.c
#include <stdio.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
// File io storing in lof file
#include "server_portLog.h"
// Thread used to create sockets
#include "sockets_pthread.h"
#define BUFFER_SIZE 1024
int main(int argc, char *argv[]) {
// Server port number
//int portNumber = atoi(argv[1]);
// sockfd: ip-address socket, newsockfd: socket from receiving client, portNum: Which port will be listening, num_bytes: received data from client
int sockfd, newsockfd, num_bytes;
// buffer: will send & receive values from the server
char buffer[BUFFER_SIZE];
struct sockaddr_in serv_addr, cli_addr;
socklen_t clilen = sizeof(cli_addr);
// Getting all ports from command line parameters and creating a socket for each
int numPorts = argc - 1;
struct port varPorts[numPorts];
pthread_t portsSockets[numPorts];
for (int i = 0; i < numPorts; i++) {
varPorts[i].portNumber = atoi(argv[i + 1]);
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_create(&portsSockets[i], &attr, createSocket, &varPorts[i]);
}
// Infinite loop too keep listening even after connection to client closes
while (1) {
// After that all the ports entered have a socket of their own the program runs them parallel together to see if any client tries to connect with one of the ports
for (int i = 0; i <= numPorts; i++) {
pthread_join(&portsSockets[i], NULL);
/* Start listening for the clients (thread blocks) */
if (listen(varPorts[i].sockfd, 5) != 0) {
printf("Error: listen() failed for port: %d \n", varPorts[i].portNumber);
//return 3;
}
// Accepting connection from client & creating socket with that client data
newsockfd = accept(varPorts[i].sockfd, (struct sockaddr *)&cli_addr, &clilen);
if (newsockfd < 0) {
printf("Error: accept() failed for port: %d \n", varPorts[i].portNumber);
//return 4;
}
/* To send receive data */
// Clearing buffer
memset(buffer, 0, BUFFER_SIZE);
// Show data received from client
num_bytes = recv(newsockfd, buffer, BUFFER_SIZE-1, 0);
if (num_bytes < 0) {
printf("Error: recv() failed for port: %d \n", varPorts[i].portNumber);
//return 5;
}
// Checking version of server if LOGFILE it creates a file to store the ports
#if defined LOGFILE
// Checking if user wrote a fileName for the logs or going to use the default log file
if (argc == 3) {
char *textFile = argv[argc-1];
serverLogFile_Custom(buffer, textFile);
}
else {
serverLogFile_Defualt(buffer);
}
#else
// Print the port numbers that connect to server
printf("Received: Client using port- %s to connect \n", buffer);
#endif
// Closing connection with client
close(newsockfd);
}
}
return 0;
}
Sockets_pthreads.h
#include <pthread.h>
struct port {
int portNumber;
int sockfd;
};
void* createSocket(void* portNumber) {
// sockfd: ip-address socket, newsockfd: socket from receiving client, portNum: Which port will be listening, num_bytes: received data from client
int sockfd, newsockfd, num_bytes;
// buffer: will send & receive values from the server
//char buffer[BUFFER_SIZE];
struct sockaddr_in serv_addr, cli_addr;
socklen_t clilen = sizeof(cli_addr);
struct port *portStruct = (struct port*) portNumber;
// Creating a new socket with ip-Protocol_tcp
// Parameters: Internet-domain, socket-stream, TCP-protocol
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockfd < 0) {
printf("Error: Failed to open socket for port: %d \n", portStruct->portNumber);
//return 1;
}
// Setting all bits in padding-field to 0
memset(&serv_addr, 0, sizeof(serv_addr));
// Initializing socket in sockaddr_in (stucture)
serv_addr.sin_family = AF_INET; // Seting family-Internet
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(portStruct->portNumber); // Setting portNum (passed in command line)
// Binding the address-structure to the socket
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
printf("Error: bind() failed for port: %d \n", portStruct->portNumber);
//return 2;
}
// Geting sockfd
portStruct->sockfd = sockfd;
pthread_exit(0);
}
Problem is not clear what needs to be implemented. If various ports sockets have to accept, then it has to happen in thread function as well as recv call. In server function there are accept and recv calls which are blocking by default.
The main function should wait for connections. Upon receiving a request from the client, you create a thread that will handle this specific connection. So you will create the threads in the loop, meaning, you can theoretically have an infinite number of threads.
However, you can add a little logic to limit the number of threads that are existing at a particular time (thread pool).
So your main loop can look like this:
while (1) {
// accept: wait for a connection request
childfd = accept(parentfd, (struct sockaddr *) &clientaddr, (socklen_t *) &clientlen);
if (childfd < 0){
fprintf(stderr,"ERROR on accept");
continue;
}
hostaddrp = inet_ntoa(clientaddr.sin_addr);
if (hostaddrp == NULL){
fprintf(stderr,"ERROR on inet_ntoa\n");
continue;
}
fprintf(stdout,"server established connection with client\n");
pthread_t new_thread;
newSock = malloc(1);
*newSock = childfd;
if( pthread_create( &new_thread , NULL , server_thread , (void*) newSock) < 0){
bzero(logMsg, MAXSTRING);
sprintf(logMsg, "Thread for connection %d could not be created",childfd);
fprintf(stderr, "%s\n", logMsg);
continue;
}
fprintf(stdout, "thread created for connection %d\n", childfd);
}
The server_thread function could look like:
void *server_thread(void* clientSock){
int childfd = *(int*)clientSock;
char buf[MAXLINE]; // message buffer
int n; // message byte size
char logMsg[MAXSTRING];
size_t siz_failresp;
// read: read input string from the client
bzero(buf, MAXLINE);
n = (int) read(childfd, buf, MAXLINE);
if (n < 0){
sprintf(logMsg, "ERROR reading from socket");
fprintf(stderr,"%s", logMsg);
close(childfd);
fprintf(stdout, "Client %d disconnected \n=================\n", childfd);
//Free the socket pointer
free(clientSock);
return NULL;
}
// else, do processing of data received...
// ...................
}
There may be unused variables here above... I just got this code from one of my projects, just removing parts that do not concern you :-)
Hope it helps

Communication: Sending a message from a client to a server

My Server can handle multiple clients/switches at a time.
My problem is in my switch I believe, I'm trying to send an open message to the the controller. I create the the tcp socket in the switch and then right after I try to send the message to the controller, however when I try to do this, the socket disconnects from the controller and goes into an infinite loop. I'm not sure why this occurs as I'm creating and sending the message outside of my while loop. If I comment where I send the message, the socket stays connected to the controller and I am able to wait for one of a set of file descriptors to become ready to perform I/O, currently I only have the keyboard and the socket. My socket also receives a message from the controller when it's connected "You are connected to the server". In addition since my switch socket disconnects my recv() return error code 107 due to the fact the socket is disconnected.
I'm not sure If I provided too much code to look through but I added comments where I thought my error was occurring in the switch as well as the controller. Greatly appreciated for some help. I didn't add any of my own header files because they are not necessary.
This where I execute the switch. Sends and receive messages here.
#include "switch.h"
#include "openFIFO.h"
#include "packets.h"
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<poll.h>
#include <signal.h>
void do_switch(int swIport, char *trafficfile,int swJport, int swKport, int IPlow, int IPhigh,char serverAddress[256], unsigned short portNumber){
int switch_sock;
char server_response[256];
struct pollfd pfds[6];
int rval;
/* Switch */
Switch sw;
sw.swJport = swJport;
sw.swIport = swIport;
sw.swKport = swKport;
sw.IPlow = IPlow;
sw.IPhigh = IPhigh;
int switchLength = sizeof(Switch);
// printf("\n\nstruct switchLength: %d\n", switchLength);
// printf("\n\nSwitch Struct: swIport: %d, swJport: %d, swKport: %d,
IPlow: %d, IPhigh: %d\n", sw.swIport, sw.swJport, sw.swKport, sw.IPlow,
sw.IPhigh);
printf("\n\nSwitch created with the following: swIport: %d, trafficfile:
%s, swJport: %d, swKport: %d, IPlow: %d, IPhigh: %d, serverAddress: %s,
portNumber: %d\n", swIport, trafficfile, swJport, swKport, IPlow, IPhigh,
serverAddress, portNumber);
int fifoWrite[2];
int fifoRead[2];
int counter = 0;
char message[20] = "Hello";
/* Create fifos */
if(swJport != -1){
fifoWrite[0] = openWF(swIport,swJport);
fifoRead[0] = openReadFifo(swJport, swIport);
counter = counter + 2;
}
if(swKport != -1){
fifoWrite[1] = openWF(swIport,swKport);
fifoRead[1] = openReadFifo(swKport, swIport);
counter = counter + 2;
}else if(swKport == -1){
fifoWrite[0] = openWF(swIport,swKport);
fifoRead[0] = openReadFifo(swKport, swIport);
counter = counter + 2;
}
printf("fifoWrite[0]: %d\n", fifoWrite[0]);
printf("fifoRead[0]: %d\n", fifoRead[0]);
printf("fifoWrite[1]: %d\n", fifoWrite[1]);
printf("fifoRead[1]: %d\n", fifoRead[1]);
/* Establish connection between the controller and switch */
/* Send a open packet to the controller */
/* Sending a stuct */
//PROBELM HERE BELOW!!!!!!!
switch_sock = CreateTCPClientSocket(portNumber, serverAddress);
if(send(switch_sock, message, sizeof(message), 0) == -1){
fprintf(stderr, "Send() Failed");
}
else{
printf("Open packet is being sent to the controller\n");
}
/* Initialize poll parameters */
//Keyboard
pfds[0].fd = STDIN_FILENO;
pfds[0].events = POLLIN;
// Socket!
pfds[1].fd = switch_sock;
pfds[1].events = POLLIN;
printf("Starting switch............................\n\n");
while(1){
rval = poll(pfds,2,-1);
if(rval == 0){
fprintf(stderr, "Poll timed out. \n");
}if(rval == -1){
fprintf(stderr, "ERROR: poll() failed");
exit(0);
}
/* Check Keyboard */
if(pfds[0].revents & POLLIN && pfds[0].fd == 0){
int a;
char command[1024][256];
int commands;
char buf[256];
commands = read(0, buf, 256);
buf[commands] = '\0';
buf[commands] = '\0';
char *token;
token = strtok(buf, " ");
while(token != NULL){
strcpy(command[a], token);
a++;
token = strtok(NULL, " ");
}
a = 0;
bzero(buf, 256);
if(strcmp(command[0], "list") == 0){
//TODO: Make a print function
printf("print_switch()\n");
}
if(strcmp(command[0], "exit") == 0){
//TODO: Make a print function
printf(" print_switch()\n");
printf("switch-disconnected\n");
close(switch_sock);
exit(0)
}
}
/* Server sent a welcome message */
// Might be PROBELM HERE BELOW when trying to send the initial packet to
controller!!!!!!!
if(pfds[1].revents & POLLIN){
recv(switch_sock, &server_response, sizeof(server_response), 0);
printf("%s\n", server_response);
}
}
}
Creates a TCP Socket for the switch.
int CreateTCPClientSocket( unsigned short port, char *serverAddress){
int sock; /*socket to create */
struct sockaddr_in servAddr; /* Local address */
/* Construct local address structure */
/* Create socket for incoming connections */
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0){
fprintf(stderr,"ERROR: socket() failed\n");
exit(0);
}
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(port);
servAddr.sin_addr.s_addr = inet_addr(serverAddress);
if(connect(sock, (struct sockaddr *)&servAddr, sizeof(struct sockaddr)) <
0){
printf("Error code: %d\n", errno);
fprintf(stderr, "ERROR: connect() just failed\n");
exit(0);
}
return sock;
}
This is the controller
#include "controller.h"
#include "packets.h"
#include "switch.h"
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
void do_controller(int nSwitch, int portNumber){
int controller_sock; /* Socket descriptor for server/controller */
int clnSocket; /*Socket descriptor for clients */
int activity;
int max_sd;
int sd;
int client_socket[nSwitch];
struct sockaddr_in address;
int addrlen;
/* Controller stuff */
Controller cont;
cont.ackCounter = 0;
cont.openCounter = 0;
Switch sw;
char message[256] = "You have reached the server\n";
char recv_message[20];
printf("\n\nController created: nSwitch: %d on portNumber: %d\n", nSwitch, portNumber);
/* Initialise all client_socket[] to 0 so not checked */
for(int i = 0; i < nSwitch; i++){
client_socket[i] = 0;
}
/*Create the server/controller socket */
controller_sock = CreateTCPServerSocket(portNumber);
//addrlen = sizeof(address);
/* Prepare for nonblocking I/O polling/select from the controller socket */
printf("Starting server.........\n\n");
while(1){
/* Zero the socket set and set for server sockets */
/* This must be reset every time select() is called */
/* Add keyboard to descriptor */
/* Add client and controller sockets to set */
FD_ZERO(&sockSet);
FD_SET(STDIN_FILENO, &sockSet);
FD_SET(controller_sock, &sockSet);
max_sd = controller_sock;
//max_sd = 0;
printf("nSwitch: %d\n", nSwitch);
for(int x = 0; x < nSwitch; x++){
sd = client_socket[x];
printf("sd: %d\n\n", sd);
if(sd > 0)
FD_SET(sd, &sockSet);
if(sd > max_sd)
max_sd = sd;
}
printf("max_sd: %d\n", max_sd);
//wait for one of the sockets, timeout is Null,
//so wait indefinitely
activity = select(max_sd + 1, &sockSet, NULL, NULL,NULL);
//printf("Activity: %d\n", activity);
if(activity < 0){
fprintf(stderr, "ERROR: select()\n");
exit(0);
}
/*Check keyboard */
if(FD_ISSET(STDIN_FILENO, &sockSet)){
int a;
char command[1024][256];
int commands;
char buf[256];
commands = read(0, buf, 256);
buf[commands] = '\0';
char *token;
token = strtok(buf, " ");
while(token != NULL){
strcpy(command[a], token);
a++;
token = strtok(NULL, " ");
}
a = 0;
bzero(buf, 256);
if(strcmp(command[0], "list") == 0){
//TODO: Make a print function
print_controller(&cont, nSwitch);
}
if(strcmp(command[0], "exit") == 0){
//TODO: Make a print function
print_controller(&cont, nSwitch);
exit(0);
}
continue;
}
/* Check the incoming FIFOS from the controller an attached switches */
/*If something happened on the controller socket,
then its an incomming connection. Accept new communitcation.Wait for a client to connect.
Recieve packets sent to the controller_sock
*/
if(FD_ISSET(controller_sock, &sockSet)){
clnSocket = AcceptTCPConnection(controller_sock);
if(send(clnSocket, message, sizeof(message), 0) != sizeof(message)){
fprintf(stderr, "Send()");
exit(0);
}
puts("Welcome message sent successfuly");
//PROBELM HERE BELOW!!!!!!! Returns error code 107 because the
socket disconnected.
recv(controller_sock, &recv_message, sizeof(recv_message), 0);
printf("This is my recv_message: %s\n", recv_message);
/*add new socket to array of sockets*/
for(int a = 0; a < nSwitch; a++){
/*if position is empty */
if(client_socket[a] == 0){
client_socket[a] = clnSocket;
printf("Adding to list of sockets as %d\n", client_socket[a]);
break;
}
}
}
/* Communicate with the sockets and handle TCP Client */
for(int z = 0; z <nSwitch; z++){
sd = client_socket[z];
/*Check if it was socket closed, and do other stuff */
if(FD_ISSET(sd ,&sockSet )){
getpeername(sd , (struct sockaddr*)&address , (socklen_t*)&addrlen);
printf("Host disconnected , ip %s , port %d \n" , inet_ntoa(address.sin_addr) , ntohs(address.sin_port));
close( sd );
client_socket[z] = 0;
}else{
//Do stuff for the client
printf("This is the client %d\n", sd);
}
}
}
}
These are the controllers functions: Assign a port to socket,Set socket to listen
int AcceptTCPConnection(int servSock){
int clntSock; /* Socket descriptor for client */
unsigned int clientAddressLen; /* sizeof(client_address); Length of client */
struct sockaddr_in cli_addr; /* Client address */
/* Set the size of the in-out parameter */
clientAddressLen = sizeof(cli_addr);
printf("ClientAddressLen: %x\n", clientAddressLen);
/* Wait for a client to connect */
if ((clntSock = accept(servSock, (struct sockaddr *) &cli_addr,
&clientAddressLen)) < 0){
fprintf(stderr, "ERROR: accept failed\n");
exit(0);
}
/* clntSock is connected to a client! */
//infrom user of socket number used in send and receive commands
printf("Handling client %s\n", inet_ntoa(cli_addr.sin_addr));
printf("New connection: socket fd is: %d, ip is: %s, port: %d\n\n",
clntSock, inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));
return clntSock;
}
Create a TCP socket
int CreateTCPServerSocket(unsigned short port){
int sock; /* socket to create */
struct sockaddr_in servAddr; /* Local address */
/* Create socket for incoming connections */
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0){
fprintf(stderr,"ERROR: socket() failed\n");
exit(0);
}
/* Construct local address structure */
/* Define the server address */
//bzero((char *) &server_address, sizeof(server_address));
memset(&servAddr, 0, sizeof(servAddr)); /* Zero out structure */
servAddr.sin_family = AF_INET; /* Internet address family
*/
servAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface
*/
servAddr.sin_port = htons(port); /* Local port */
/* Bind to the local address */
printf("New connection: ip is: %s, port: %d\n\n",
inet_ntoa(servAddr.sin_addr), ntohs(servAddr.sin_port));
if (bind(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0){
printf("Error code: %d\n", errno);
fprintf(stderr,"ERROR: bind() just failed\n");
exit(0);
}
/* Mark the socket so it will listen for incoming connections */
if (listen(sock, 5) < 0){
fprintf(stderr,"ERROR: listen() failed\n");
exit(0);
}
return sock;
}

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

C program only write into files when debugging

I am writing a simple code to test thread pools. I have a client sendin lines of data to server through different ports.
Some threads receive the data, then send them to other threads for processing.
For now, the only processing I am doing is just to write the data into a file.
Here is the code of the worker thread.
void* worker_thread(void* arg){
int i, workerNum;
pthread_t worker_id = pthread_self();
char *ticket = (char*) arg;
char dumpfile[50];
for(i=0;i<10;i++)
if(pthread_equal(worker_id, id_pool[i]))
break;
if(10==i){
pthread_exit(NULL);
}
workerNum = i;
fprintf(stdout, "Worker [%d] busy\n",workerNum);
sprintf(dumpfile, "worker_%d.log",workerNum);
if(strlen(ticket)<4){
fprintf(stdout, "Worker [%d] RELEASED!!\n",workerNum);
poolStatus[workerNum] = 0;
pthread_mutex_unlock(&mutexes[workerNum]);
pthread_exit(NULL);
}
FILE *logFile = fopen(dumpfile, "a+");
// ticket[strlen(ticket)]
fprintf(logFile, "%s\n", ticket);
fclose(logFile);
sleep(workerNum+2);
poolStatus[workerNum] = 0;
fprintf(stdout, "Worker [%d] RELEASED!!\n",workerNum);
pthread_mutex_unlock(&mutexes[workerNum]);
pthread_exit(NULL);
}
The code works when I run through a debugger (GDB, under linux). When I run it simply on the command line, it runs but does not create the files!
Can you please assist?
the complete code:
#include <time.h>
#include <errno.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <strings.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define BUFSIZE 65535
#define NUMWORKERS 10
static pthread_mutex_t mutexes[NUMWORKERS];
pthread_t id_pool[NUMWORKERS], id_servers[6];
int serverports[6] = {22191, 22192, 22193, 7525, 7526, 7527};
char poolStatus[NUMWORKERS] = {0};
void error(char *msg) {
FILE *logFile = fopen("errorlog.log", "a+");
fprintf(logFile, "%s\n", msg);
fclose(logFile);
exit(1);
}
void* serverListener(void* arg);
void* worker_thread(void* arg);
int main(){
int i, t_err[6];
for(i=0; i< NUMWORKERS; i++)
pthread_mutex_init(&mutexes[i],NULL);
for(i=0; i<6; i++){
t_err[i] = pthread_create(&id_servers[i], NULL, serverListener, NULL);
}
pthread_join(id_servers[5], NULL);
return 0;
}
void* serverListener(void* arg){
int parentfd, childfd; // parent socket & child socket
int portno, clientlen; // port number and size of client address
struct sockaddr_in serveraddr;
struct sockaddr_in clientaddr;// server and client addresses
struct hostent *hostp; // client host info
char buf[BUFSIZE]; // message buffer
char *hostaddrp; // dotted decimal host addr string
int optval, n; // flag value for setsockopt and message byte size
unsigned int CLOCKREF, CLOCKCOUNT;
pthread_t id = pthread_self(); // own thread id
int threadNumber, i=0; // thread number linked to ort to listen to.
char dumpfile[50];
for(i=0; i<6; i++) if(pthread_equal(id, id_servers[i])) break;
threadNumber = i;
portno = serverports[threadNumber];
sprintf(dumpfile, "receiver_%d.log",portno);
// socket: create the parent socket
parentfd = socket(AF_INET, SOCK_STREAM, 0);
if (parentfd < 0)
error("ERROR opening socket");
optval = 1;
setsockopt(parentfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval , sizeof(int));
// build the server's Internet address
bzero((char *) &serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
// let the system figure out our IP address
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
// this is the port we will listen on
serveraddr.sin_port = htons((unsigned short)portno);
// bind: associate the parent socket with a port
if (bind(parentfd, (struct sockaddr *) &serveraddr,
sizeof(serveraddr)) < 0)
error("ERROR on binding");
// listen: make this socket ready to accept connection requests
if (listen(parentfd, 5) < 0) /* allow 5 requests to queue up */
error("ERROR on listen");
// main loop: wait for a connection request
clientlen = sizeof(clientaddr);
while (1) {
// accept: wait for a connection request
childfd = accept(parentfd, (struct sockaddr *) &clientaddr, &clientlen);
if (childfd < 0)
error("ERROR on accept");
// gethostbyaddr: determine who sent the message
hostp = gethostbyaddr((const char *)&clientaddr.sin_addr.s_addr,
sizeof(clientaddr.sin_addr.s_addr), AF_INET);
if (hostp == NULL)
error("ERROR on gethostbyaddr");
hostaddrp = inet_ntoa(clientaddr.sin_addr);
if (hostaddrp == NULL)
error("ERROR on inet_ntoa\n");
fprintf(stdout, "server established connection with %s (%s)\n", hostp->h_name, hostaddrp);
// read: read input string from the client
CLOCKREF = (unsigned int)time(NULL);
int counter = 0;
while(1){
CLOCKCOUNT = (unsigned int)time(NULL) - CLOCKREF;
bzero(buf, BUFSIZE);
n = read(childfd, buf, BUFSIZE);
if (n < 0) error("ERROR reading from socket");
if(0==n) counter++;
if(3<=counter) {
close(childfd);
return;
}
int busyWorker = 1;
i = 0;
while(busyWorker){
if(i>=NUMWORKERS) i = 0;
if(pthread_mutex_trylock(&mutexes[i])==0){ // not locked, can be used
fprintf(stdout, "port [%d] sends to thread [%d]\n", portno, i);
pthread_create(&id_pool[i], NULL, worker_thread, (void*)buf);
busyWorker = 0;
break;
}
i++;
}
}
close(childfd);
}
}
void* worker_thread(void* arg){
int i, workerNum;
pthread_t worker_id = pthread_self();
char *ticket = (char*) arg;
char dumpfile[50];
for(i=0;i<10;i++)
if(pthread_equal(worker_id, id_pool[i]))
break;
if(10==i){
pthread_exit(NULL);
}
workerNum = i;
fprintf(stdout, "Worker [%d] busy\n",workerNum);
sprintf(dumpfile, "worker_%d.log",workerNum);
if(strlen(ticket)<4){
fprintf(stdout, "Worker [%d] RELEASED!!\n",workerNum);
poolStatus[workerNum] = 0;
pthread_mutex_unlock(&mutexes[workerNum]);
pthread_exit(NULL);
}
FILE *logFile = fopen(dumpfile, "a+");
// ticket[strlen(ticket)]
fprintf(logFile, "%s\n", ticket);
fclose(logFile);
sleep(workerNum+2);
poolStatus[workerNum] = 0;
fprintf(stdout, "Worker [%d] RELEASED!!\n",workerNum);
pthread_mutex_unlock(&mutexes[workerNum]);
pthread_exit(NULL);
}
I believe I have found the problem!!
To pass a message from serverListener thread to worker_thread, I used the pointer to buffer used to read from the socket. Problem is, before the worker_thread could process it, the serverListener has reset the value to zero ( bzero(buf, BUFSIZE) ) ! and given the fact that the worker_thread must only write to file when the size is greater than 4, it doesn't write it.
so to solve my problem, I replaced the line:
pthread_create(&id_pool[i], NULL, worker_thread, (void*)buf);
by:
char *msg2send = strdup(buf);
pthread_create(&id_pool[i], NULL, worker_thread, (void*)msg2send);
And it did the trick!!
Still does not really explain why it could create the files in debug mode though...

Resources