Data sending error in socket - c

I have made simple server and client in c.Client waits for server until server is started.When i start the server data transmission between server and client is happening as per my expectation.When i close the server(not client) and again restarts the server,the first string from client to server is not transmitting.and then afterwards the client can send strings to server.So after restarting server client can't transmit first string to server.
Here is my client code(client.c),
/*header*/
#include<signal.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
/*macros*/
/*size of the buffer*/
#define DATA_SIZE 200
/*function for thread*/
void *recieve_handler(void *);
/*stores the id of main thread*/
pthread_t main_id;
/*socket variable*/
int sockfd=0;
/*specifies the port number*/
#define PORT 5000
/*lenth of ip*/
#define LENGTH_OF_IP 100
int quit = 1;
void signal_handler(int n)
{
/*write null to server*/
write(sockfd,"",2);
/*close socket*/
close(sockfd);
printf("Exiting from applicationn");
exit(0);
}
int main(int argc, char *argv[])
{
/*buffer to send and receive*/
char received_data[DATA_SIZE],send_data[DATA_SIZE],server_ip[LENGTH_OF_IP],buf[DATA_SIZE]
,user_name[DATA_SIZE];
/*declare pointer for client config file*/
FILE* config_file;
/*flags*/
int clear = 1,server_port,usb_trap_on,n;
/*declaring socket object*/
struct sockaddr_in serv_addr;
/*thread declaration*/
pthread_t thread_id;
/*welcome messsage*/
printf("This is clientn");
printf("Enter somethingn");
printf("Server echos back the datan");
/*open client configuration file*/
if ((config_file = fopen("client.config","rw+")) == NULL)
{
printf("Could not open client config filen");
return 1;
}
/*parsing the file*/
while (fgets(buf, sizeof buf, config_file) != NULL) {
if (sscanf(buf,"IP=%s PORT=%d",server_ip,&server_port) == 2)
printf("%s %dn",server_ip,server_port);
if (fscanf(config_file,"usb_trap=%d",&usb_trap_on) == 1)
printf("usb flag is %dn",usb_trap_on);
}
/*create the socket*/
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
printf("n Error : Could not create socket n");
return 1;
}
/*By setsockopt kernal will release the socket
*if it is in use*/
if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&clear,sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
/*inialize all the variable of object serv_addr with 0*/
memset(&serv_addr, '0', sizeof(serv_addr));
/*AF_INET refers to addresses from the internet*/
serv_addr.sin_family = AF_INET;
/*specifies port address
*and The htons() function makes sure that numbers are stored
*in memory in network byte order, which is with the most
*significant byte first*/
serv_addr.sin_port = htons(server_port);
/* inet_pton - convert IPv4 and IPv6 addresses from text to binary form
* it returns 0 when coversion is unsucessful*/
if(inet_pton(AF_INET, server_ip, &serv_addr.sin_addr)<=0){
printf("n inet_pton error occuredn");
return 1;
}
/*connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))
*if connection is established then the memory for server will be
*allocated in client's memory
*and strting address of that memory is stored in scokfd
*i will return negative value if operation fails. */
while(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){
printf("Wating for server to connectn");
sleep(1);
}
printf("Connection is donen");
printf("enter somethingn");
/*signal handling*/
signal(SIGTSTP,signal_handler);
/*create the thread to receive data*/
if( pthread_create( &thread_id , NULL , recieve_handler , (void*)&sockfd) < 0) {
perror("could not create thread");
return 1;
}
while(1) {
/*clear the buffer*/
memset(received_data,0,DATA_SIZE);
/*read from server*/
n = read(sockfd,received_data,sizeof(received_data));
/*if read error is occurred*/
if (n < 0) {
printf("Can't read received_datan");
break;
pthread_exit(&n);
}
if(n == 0) {
printf("Can't read received_datan");
break;
}
puts(received_data);
}
pthread_cancel(&thread_id);
/*close socket*/
if(!close(sockfd))
printf("Socket is closedn");
printf("Server is sutdown!!!!!!!!!!!!!n");
system("./client");
return 0;
}
void *recieve_handler(void *socket_desc)
{
/*received data buffer*/
char send_data[DATA_SIZE];
/*status flag*/
int n;
/*if pointer is empty*/
if(socket_desc == NULL) {
printf("socket_desc is NULLn");
n = 0;
pthread_exit(&n);
}
/*socket number*/
int sock = *(int*)socket_desc;
/*infinite loop*/
while (1){
/*clear buffer*/
memset(send_data, '0', sizeof(send_data));
/*get data from user*/
gets(send_data);
if((write(sock, send_data, strlen(send_data)+1)) == -1)
{
/*write data to server*/
printf("could not writen");
break;
}
}
}
here is my server code(server.c),
/*header*/
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
/*macros*/
/*maximum client that can be connected to server*/
#define MAX_CLIENT 10
/*size of the buffer*/
#define DATA_SIZE 200
/*specifies the port number*/
#define PORT 7000
int listenfd;
void signal_handler(int n)
{
printf("In handler\n");
char recived_data[DATA_SIZE];
write(listenfd,"\0",2);
read(listenfd, recived_data, sizeof(recived_data));/*write null to server*/
write(listenfd,"\0",2);
/*close socket*/
close(listenfd);
printf("Exiting from application\n");
exit(0);
}
int main(int argc, char *argv[])
{
/*signal handling*/
signal(SIGTSTP,signal_handler);
/*to store the recived data*/
char recived_data[DATA_SIZE];
/*sockaddr_in is a structure defined in netinet/in.h file.we are creating object of that
*strucure. */
struct sockaddr_in serv_addr;
/*flags*/
int connfd = 0 , clear = 1 ;
/*welcome message*/
printf("This simple server\n");
printf("It will echo data to client\n");
printf("If quit is recived from client then server will be existed\n");
/*Created socket*/
if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
printf("Can't create socket\n");
}
/*By setsockopt kernal will release the socket
*if it is in use*/
if (setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&clear,sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
/*AF_INET refers to addresses from the internet*/
serv_addr.sin_family = AF_INET;
/*tells that any client can connect*/
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
/*specifies port address
*and The htons() function makes sure that numbers are stored
*in memory in network byte order, which is with the most
*significant byte first*/
serv_addr.sin_port = htons(PORT);
/*specifies port and adress of the socket*/
bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
/*it will listen for connection
*MAX_CLIENT specifies the maximum client server can handle*/
listen(listenfd, MAX_CLIENT);
/*accept will assign the memory to client in server's memory area.here
*connfd has starting adress of assigned memory to client in server
*memory.*/
connfd = accept(listenfd, (struct sockaddr*)NULL, NULL);
/*inet_ntoa(serv_addr.sin_addr) will return the adress of client*/
printf("[Server] Server has got connected from %s.\n", inet_ntoa(serv_addr.sin_addr));
printf("server waiting\n");
while(1){
/*read the data from memory and put in buffer*/
if(read(connfd, recived_data, sizeof(recived_data))){
/*if quit is recived then break the loop*/
if(!strcmp(recived_data,"quit"))
break;
/*put data on screen*/
puts(recived_data);
/*echo the data back to client*/
if(write(connfd,recived_data,strlen(recived_data)+1) == -1)
break;
}
else
{
printf("Could not read\n");
}
}
read(connfd, recived_data, sizeof(recived_data));
printf("server exiting\n");
/*close socket*/
close(connfd);
return(0);
}
here is client.config file(which is used be client to get ip,port of server)
IP=192.168.3.17 PORT=7000
usb_trap=0
This is my output of client when server is first time connected,
This is client
Enter something
Server echos back the data
192.168.3.17 7000
usb flag is 0
Wating for server to connect
Wating for server to connect
Connection is done
enter something
hello
hello
i am jay
i am jay
Above output is as per my expectation.
Now below is my output of client when server is reconnected(server is disconnected ,and then started again)
Socket is closed
Server is sutdown!!!!!!!!!!!!!
This is client
Enter something
Server echos back the data
192.168.3.17 7000
usb flag is 0
Wating for server to connect
Wating for server to connect
Wating for server to connect
Wating for server to connect
Connection is done
enter something
hello
could not write
jay
jay
So in above output client can't write first string to server.

Client signal handler:
void signal_handler(int n)
{
/*write null to server*/
write(sockfd,"",2);
/*close socket*/
close(sockfd);
printf("Exiting from applicationn");
exit(0);
}
Everything wrong here that could be wrong. No error checking. You can't do I/O in signal handlers. You can't block in signal handlers. You don't need to 'write null to server'. Exiting the application will close the socket, or reset it.
Client:
while(1) {
/*clear the buffer*/
memset(received_data,0,DATA_SIZE);
Unnecessary. Remove.
if (n < 0) {
printf("Can't read received_datan");
A pointless message. You got an error. Print the error, with perror(), or by incorporating strerror() into the message.
if(n == 0) {
printf("Can't read received_datan");
An incorrect message. This situation is not the same as the previous one. You got end of stream. The peer has disconnected. Say so.
puts(received_data);
Wrong. The data received is only valid up to n bytes. The correct way to print it is via printf("%.*s", n, received_data);
Client 'receive handler':
void *recieve_handler(void *socket_desc)
Apart from the mis-spelling, why is this called a receive handler when it doesn't receive? and does send?
memset(send_data, '0', sizeof(send_data));
/*get data from user*/
gets(send_data);
You probably meant '\0' here, as there are numerous other backslashes missing from your code, but the memset() is completely unnecessary. Remove.
Server signal handler:
void signal_handler(int n)
{
printf("In handler\n");
char recived_data[DATA_SIZE];
write(listenfd,"\0",2);
read(listenfd, recived_data, sizeof(recived_data));/*write null to server*/
write(listenfd,"\0",2);
/*close socket*/
close(listenfd);
printf("Exiting from application\n");
exit(0);
}
This is all nonsense from start to finish. You can't do I/O in a signal handler; you can't do I/O with a listening socket; you can't block in a signal handler; and you don't need to do any of it. The operating system will either close or reset the socket. Either way the peer will find out via the return value of read() or recv().
Server loop:
if(read(connfd, recived_data, sizeof(recived_data))){
Incorrect. It is never correct to call read() or recv() without storing the return value into a variable. You have to test it for -1, test it for zero, and otherwise use it as the length of data received. You can't accomplish that without a variable. See your own client code for an example, after my corrections.
if(!strcmp(recived_data,"quit"))
Invalid. There is no guarantee that you will receive a null-terminated string. And you haven't checked for EOS or an error first.
puts(recived_data);
Invalid for the same reason as the puts() in the client as discussed above.
if(write(connfd,recived_data,strlen(recived_data)+1) == -1)
Invalid. The length of the data received is given by the return value of read() if positive, not by strlen(). See discussion above.
else
{
printf("Could not read\n");
}
See discussion above about indiscriminate error messages like this. No use at all.
read(connfd, recived_data, sizeof(recived_data));
What is this? Remove.

Problem is that you are not canceling the thread properly.
Use
pthread_cancel(thread_id);
instead of
pthread_cancel(&thread_id);
So now thread will be canceled.and that thread will not be lived.

Related

Simple echo program using sockets in C echoing incorrect message after the first run

I am trying to learn the basic of network communication using sockets in C. My client program takes in a message from the user, echoes it server side and back, and prints out the received message. When I fire both of them up for the first time, they both work exactly as expected. However, if I quit the client side and then fire it up again while keeping the server program running, my echoed messages become off by one.
I assumed it was because the last message is getting caught in the pipe or something, and after poking around, I saw that someone suggested to use shutdown() to flush out the pipe, but that doesn't seem to be working. I also tried to zero out the buffers wherever I thought they may be lingering, but that didn't seem to help, either.
server.c
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#define PORT 12403
#define BUFFER_MAX 1024
#define BACKLOG_MAX 1024
int clientSocket;
int serverSocket;
void listening()
{
while (1)
{
struct sockaddr_in clientAddress;
socklen_t addressLength = sizeof(clientAddress);
/*---accept a connection (creating a data pipe)---*/
clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddress, &addressLength);
if (clientSocket > -1)
{
printf("%s:%d connected\n", inet_ntoa(clientAddress.sin_addr), ntohs(clientAddress.sin_port));
break;
}
}
}
int main(int Count, char *Strings[])
{
struct sockaddr_in socketInfo;
char buffer[BUFFER_MAX];
//Create socket
if ((serverSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("Error creating socket");
exit(errno);
}
//Setting the linger option to off and resuse address option to on for testing
int option = 0;
setsockopt(serverSocket, SOL_SOCKET, SO_LINGER, &option, sizeof(option));
option = 1;
setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
//Initialize socket information
bzero(&socketInfo, sizeof(socketInfo));
socketInfo.sin_family = AF_INET;
socketInfo.sin_port = htons(PORT);
socketInfo.sin_addr.s_addr = INADDR_ANY;
//Assign a port number to the socket
if (bind(serverSocket, (struct sockaddr*)&socketInfo, sizeof(socketInfo)) != 0)
{
perror("Error binding socket");
exit(errno);
}
//Set socket to listen
if (listen(serverSocket, BACKLOG_MAX) != 0)
{
perror("Error setting socket to listen");
exit(errno);
}
listening();
//Once first socket has been connected, begin echoing process
int i = 0;
while (1)
{
//Clear the buffer
bzero(buffer, BUFFER_MAX);
//Echo back anything sent
//Close connection and begin listening process again if the client disconnects
int sendCheck;
int readCheck;
readCheck = recv(clientSocket, buffer, BUFFER_MAX, 0);
if (readCheck <= 0)
{
shutdown(clientSocket, SHUT_WR);
close(clientSocket);
sleep(1);
listening();
}
sendCheck = send(clientSocket, buffer, BUFFER_MAX, 0);
if (sendCheck <= 0)
{
shutdown(clientSocket, SHUT_WR);
close(clientSocket);
sleep(1);
listening();
}
i++;
}
close(serverSocket);
return 0;
}
client.c
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <stdlib.h>
#include <resolv.h>
#include <netdb.h>
#define PORT 12403
#define LOCALHOST "127.0.0.1"
#define BUFFER_MAX 1024
int socketStatus = 0;
void sigpipeHandler()
{
perror("Connection to server terminated\n");
socketStatus = 0;
}
int main()
{
int mySocket;
struct sockaddr_in socketInfo;
char buffer[BUFFER_MAX];
int count = 0;
//Create socket
if ((mySocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("Error creating socket");
exit(errno);
}
//Get IP address of required host machine
char* hostName = "<host name removed>";
int portNumber = PORT;
char* ipAddr = NULL;
struct hostent* host = NULL;
host = gethostbyname(hostName);
ipAddr = inet_ntoa(*((struct in_addr*) host->h_addr_list[0]));
//Initialize server information
bzero(&socketInfo, sizeof(socketInfo));
socketInfo.sin_family = AF_INET;
socketInfo.sin_port = htons(portNumber);
if (inet_aton(ipAddr, (struct in_addr *)&socketInfo.sin_addr.s_addr) == 0)
{
perror("Error assigning IP address");
exit(errno);
}
//Set up sigpipe handler
signal(SIGPIPE, sigpipeHandler);
//Connect to server
if (connect(mySocket, (struct sockaddr*)&socketInfo, sizeof(socketInfo)) != 0)
{
perror("Error connecting");
exit(errno);
}
//Indicate that socket is OK
socketStatus = 1;
while(1)
{
if(!socketStatus) {shutdown(mySocket, SHUT_WR); break;}
printf("Please enter a command.\n");
char command[BUFFER_MAX];
bzero(command, BUFFER_MAX);
fgets(command, sizeof(command), stdin);
send(mySocket, command, BUFFER_MAX, 0);
//Get echoed message
bzero(buffer, BUFFER_MAX);
recv(mySocket, buffer, sizeof(buffer), 0);
printf("Echo [%d]:%s\n", ++count, buffer);
}
//Close socket
close(mySocket);
return 0;
}
I did some cleanup on your server code and this seems to work.
For my testing, the client code is unchanged. But, as others have suggested, you should check the error codes from send and recv. Also, note that if you ctrl-c the server, the client will hang in the fgets, so it won't detect the server abort until you hit return after the prompt. Not a big deal, but I thought I'd mention it.
I also added a fork so you can have multiple clients talking to the same server instance simultaneously.
I tested this with two clients [in two xterm windows] talking with the single server instance.
I moved your echo code into a new function docomm. A small difference from your code is that any error from either recv or send breaks out of the loop and closes the connection. All connections from new clients are guaranteed to start with a recv call.
In your code, you would not always break out of the loop, but close the connection and call listening again. This would happen for either send or recv. If it happened on the wrong one, this might be the source of the problem you were having because you could do a send before a recv to a new client initially.
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <sys/wait.h>
#define PORT 12403
#define BUFFER_MAX 1024
#define BACKLOG_MAX 1024
int clientSocket;
int serverSocket;
int forkflg = 1;
void listening()
{
while (1)
{
struct sockaddr_in clientAddress;
socklen_t addressLength = sizeof(clientAddress);
/*---accept a connection (creating a data pipe)---*/
clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddress, &addressLength);
if (clientSocket > -1)
{
printf("%s:%d connected\n", inet_ntoa(clientAddress.sin_addr), ntohs(clientAddress.sin_port));
break;
}
}
}
void
docomm(void)
{
char buffer[BUFFER_MAX];
//Once first socket has been connected, begin echoing process
int i = 0;
while (1) {
//Clear the buffer
bzero(buffer, BUFFER_MAX);
//Echo back anything sent
//Close connection and begin listening process again if the client disconnects
int sendCheck;
int readCheck;
readCheck = recv(clientSocket, buffer, BUFFER_MAX, 0);
if (readCheck <= 0)
break;
sendCheck = send(clientSocket, buffer, BUFFER_MAX, 0);
if (sendCheck <= 0)
break;
i++;
}
printf("close\n");
shutdown(clientSocket, SHUT_WR);
close(clientSocket);
}
int main(int Count, char *Strings[])
{
struct sockaddr_in socketInfo;
//Create socket
if ((serverSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("Error creating socket");
exit(errno);
}
//Setting the linger option to off and resuse address option to on for testing
int option = 0;
setsockopt(serverSocket, SOL_SOCKET, SO_LINGER, &option, sizeof(option));
option = 1;
setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
//Initialize socket information
bzero(&socketInfo, sizeof(socketInfo));
socketInfo.sin_family = AF_INET;
socketInfo.sin_port = htons(PORT);
socketInfo.sin_addr.s_addr = INADDR_ANY;
//Assign a port number to the socket
if (bind(serverSocket, (struct sockaddr*)&socketInfo, sizeof(socketInfo)) != 0)
{
perror("Error binding socket");
exit(errno);
}
//Set socket to listen
if (listen(serverSocket, BACKLOG_MAX) != 0)
{
perror("Error setting socket to listen");
exit(errno);
}
while (1) {
listening();
if (! forkflg) {
docomm();
continue;
}
pid_t pid = fork();
if (pid == 0) {
docomm();
exit(0);
}
while (waitpid(0,NULL,WNOHANG) > 0);
}
close(serverSocket);
return 0;
}
UPDATE:
Just from a glance: 1) Can I ask why you created a fork flag if you never change the value of it? Should it be changed somewhere?
I used forkflg so you can set it to zero (e.g. int forkflg = 0;) to run sequentially. Or, you could add some code and parse argv looking for an option (e.g. -f) to set/clear it [for testing/debug purposes]. For production code, you'd want forkflg to be set and could remove the flag and just do the fork case always [adjusting the code to match].
Just tracing through the program mentally, it seems like the forking section will never be executed. Correct me where I'm wrong: after initially setting the socket to listen, the while loop will enter, and listening() will be called. Execution will halt in listening() until a connection is accepted.
Yes, that's true.
Control will return to main, where docomm() gets called. Control stays in docomm() until the connection breaks, at which point it returns to main and continue gets called, skipping the fork stuff and starting the process over again. So does the fork stuff ever get executed?
What you're describing is the behavior if forkflg is zero.
The fork is called if forkflg is set. Note that, in that case, docomm is called in the child and not the parent (because fork returned 0). So, the parent will not be blocked while the child does the echoing.
Thus, the parent returns immediately and is free to do the waitpid loop to reap any old children and restart the main/outer loop.
The waitpid loop only happens when a new connection comes in, so several children may have already terminated and will stay in zombie state until the waitpid loop gets executed [which will reap any/multiple pending children].
A cleaner way to reap the children might be to set up a signal handler for SIGCHLD and have it do the waitpid loop. This would reap all spent children immediately, without having to wait for a new connection to roll in.
Or, with the signal handler, add the waitpid loop to listening [inside the current loop] because if a SIGCHLD signal comes in, accept will return immediately with errno set to EINTR

Unable to connect with multiple client with my socket server program

My socket server program is mentioned below. It works fine with the single client but when I try to connect it with another client at the same time, I am unable to connect. But I have defined MAX_CLIENTS in my program as 2 but still why I am unable to connect with multiple clients? What is the correct process to connect with multiple client? Will I be able to connect with multiple client by modifying this code? Any possible fix?
Socket Server Code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <error.h>
#include <strings.h>
#include <unistd.h>
#include <arpa/inet.h>
#define ERROR -1
#define MAX_CLIENTS 2
#define MAX_DATA 1024
main (int argc, char **argv){
struct sockaddr_in server;
struct sockaddr_in client;
int sock;
int new;
int sockaddr_len = sizeof (struct sockaddr_in);
int data_len;
char data [MAX_DATA];
if ((sock = socket (AF_INET, SOCK_STREAM, 0)) == -1)
{
perror ("socket: ");
exit (-1);
}
printf("after socket");
server.sin_family = AF_INET;
server.sin_port = htons(atoi(argv[2]));
server.sin_addr.s_addr = INADDR_ANY;
bzero (&server.sin_zero, 8);
printf("after server");
if ((bind (sock, (struct sockaddr*)&server, sockaddr_len)) == -1)
{
perror ("bind");
exit (-1);
}
printf("after bind");
if ((listen(sock, MAX_CLIENTS)) == ERROR)
{
perror ("listen");
exit (-1);
}
printf("after listen");
while(1)
{
if ((new = accept(sock, (struct sockaddr*)&client, &sockaddr_len)) == ERROR)
{
perror ("accept");
exit (-1);
}
printf("after new");
printf("New client connected from port no %d and IP %s\n",ntohs(client.sin_port), inet_ntoa(client.sin_addr));
data_len = 1;
while (data_len)
{
data_len = recv (new, data, MAX_DATA, 0);
if (data_len)
{
send (new, data, data_len, 0) ;
data [data_len]='\0';
printf("Sent mesg: %s", data);
}
printf("after datalen");
}
printf("Client Disconnected\n");
close(new);
}
printf("after close new");
close (sock);
}
Your program is single-threaded, and only does one thing at a time. When you have accepted a socket connection from a client (in your outer while loop) you start communicating with that client (in your inner while loop), and you don't get back to the accept call until the first client has disconnected.
Either use threads, with one thread that waits for new connections and one additional thread for each client, waiting for input from that client, or use the select call, which lets you wait for input simultaneously from several different sources.

Problem in udp socket programing in c

I complile the following C code of UDP client
after I run './udpclient localhost 9191' in terminal.I put "Enter Text= " as Hello, but it is showing error in sendto as below:
Enter text: hello
hello
: error in sendto()guest-1SDRJ2#md-K42F:~/Desktop$
"
Note: I open 1st the server port as below in other terminal
./server 9191.
I beleive there is no error in server code. The udp client is not passing message to server. If I don't use thread , the message is passing .But I have to do it by thread.
UDP client Code:
/* simple UDP echo client */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <pthread.h>
#define STRLEN 1024
static void *readdata(void *);
static void *writedata(void *);
int sockfd, n, slen;
struct sockaddr_in servaddr;
char sendline[STRLEN], recvline[STRLEN];
int main(int argc, char *argv[]) {
pthread_t readid,writeid;
struct sockaddr_in servaddr;
struct hostent *h;
if(argc != 3) {
printf("Usage: %s <proxy server ip> <port>\n", argv[0]);
exit(0);
}
/* create hostent structure from user entered host name*/
if ( (h = gethostbyname(argv[1])) == NULL) {
printf("\n%s: error in gethostbyname()", argv[0]);
exit(0);
}
/* create server address structure */
bzero(&servaddr, sizeof(servaddr)); /* initialize it */
servaddr.sin_family = AF_INET;
memcpy((char *) &servaddr.sin_addr.s_addr, h->h_addr_list[0], h->h_length);
servaddr.sin_port = htons(atoi(argv[2])); /* get the port number from argv[2]*/
/* create a UDP socket: SOCK_DGRAM */
if ( (sockfd = socket(AF_INET,SOCK_DGRAM, 0)) < 0) {
printf("\n%s: error in socket()", argv[0]);
exit(0);
}
pthread_create(&readid,NULL,&readdata,NULL);
pthread_create(&writeid,NULL,&writedata,NULL);
while(1)
{
};
close(sockfd);
}
static void * writedata(void *arg)
{
/* get user input */
printf("\nEnter text: ");
do {
if (fgets(sendline, STRLEN, stdin) == NULL) {
printf("\n%s: error in fgets()");
exit(0);
}
/* send a text */
if (sendto(sockfd, sendline, sizeof(sendline), 0, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) {
printf("\n%s: error in sendto()");
exit(0);
}
}while(1);
}
static void * readdata(void *arg)
{
/* wait for echo */
slen = sizeof(servaddr);
if ( (n = recvfrom(sockfd, recvline, STRLEN, 0, (struct sockaddr *) &servaddr, &slen)) < 0) {
printf("\n%s: error in recvfrom()");
exit(0);
}
/* null terminate the string */
recvline[n] = 0;
fputs(recvline, stdout);
}
The problem is that you're using the same sockaddr struct (servaddr) for both the sendto and revfrom calls. The recvfrom happens first, so it clears out servaddr in preparation for writing in the source address of the received packed (once it receives one -- that thread is still blocked in the kernel waiting for a packet). Then, when the sendto call occurs, the sockaddr is all zeros, so it immediately returns EINVAL.
You may be getting confused by the fact that the sockaddr argument to recvfrom is an OUTPUT, not an input -- it gets filled in with the source address of the packet that is received (which could be from anywhere). If you want to only receive packets from a particular place (the server?), you need to check the address after the recvfrom returns and toss the packet if it comes from somewhere else, looping back to recvfrom again.

File transfer using TCP on Linux

I'm trying TCP file transfer on Linux. After establishing the connection, the server should send "send.txt" to the client, and the client receives the file and saves it as "receive.txt". Then the connection breaks.
The correct input and output should be:
Server terminal:
$./server &
[server] obtain socket descriptor successfully.
[server] bind tcp port 5000 in addr 0.0.0.0 successfully.
[server] listening the port 5000 successfully.
[server] server has got connect from 127.0.0.1.
[server] send send.txt to the client…ok!
[server] connection closed.
Client terminal:
$./client
[client] connected to server at port 5000…ok!
[client] receive file sent by server to receive.txt…ok!
[client] connection lost.
And both the server and client should exit after the process.
But what I've got now gives
$ ./server &
[server] obtain socket descriptor successfully.
[server] bind tcp port 5000 in addr 0.0.0.0 sucessfully.
[server] listening the port 5000 sucessfully.
[server] server has got connect from 127.0.0.1.
[server] send send.txt to the client...ok!
[server] connection closed.
/*Here the server doesn't exit*/
$ ./client
[client] connected to server at port 5000...ok!
/*Here the client doesn't exit*/
Also, an EMPTY "receive.txt" is generated.
My code was first written for transferring simple strings, and it worked correctly. So I guess the problem lies in the file transferring part.
My code is as follows:
server.c
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <sys/socket.h>
#define PORT 5000 // The port which is communicate with server
#define BACKLOG 10
#define LENGTH 512 // Buffer length
int main ()
{
int sockfd; // Socket file descriptor
int nsockfd; // New Socket file descriptor
int num;
int sin_size; // to store struct size
struct sockaddr_in addr_local;
struct sockaddr_in addr_remote;
/* Get the Socket file descriptor */
if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
{
printf ("ERROR: Failed to obtain Socket Descriptor.\n");
return (0);
}
else printf ("[server] obtain socket descriptor successfully.\n");
/* Fill the local socket address struct */
addr_local.sin_family = AF_INET; // Protocol Family
addr_local.sin_port = htons(PORT); // Port number
addr_local.sin_addr.s_addr = INADDR_ANY; // AutoFill local address
bzero(&(addr_local.sin_zero), 8); // Flush the rest of struct
/* Bind a special Port */
if( bind(sockfd, (struct sockaddr*)&addr_local, sizeof(struct sockaddr)) == -1 )
{
printf ("ERROR: Failed to bind Port %d.\n",PORT);
return (0);
}
else printf("[server] bind tcp port %d in addr 0.0.0.0 sucessfully.\n",PORT);
/* Listen remote connect/calling */
if(listen(sockfd,BACKLOG) == -1)
{
printf ("ERROR: Failed to listen Port %d.\n", PORT);
return (0);
}
else printf ("[server] listening the port %d sucessfully.\n", PORT);
int success = 0;
while(success == 0)
{
sin_size = sizeof(struct sockaddr_in);
/* Wait a connection, and obtain a new socket file despriptor for single connection */
if ((nsockfd = accept(sockfd, (struct sockaddr *)&addr_remote, &sin_size)) == -1)
printf ("ERROR: Obtain new Socket Despcritor error.\n");
else printf ("[server] server has got connect from %s.\n", inet_ntoa(addr_remote.sin_addr));
/* Child process */
if(!fork())
{
char* f_name = "send.txt";
char sdbuf[LENGTH]; // Send buffer
printf("[server] send %s to the client...", f_name);
FILE *fp = fopen(f_name, "r");
if(fp == NULL)
{
printf("ERROR: File %s not found.\n", f_name);
exit(1);
}
bzero(sdbuf, LENGTH);
int f_block_sz;
while((f_block_sz = fread(sdbuf, sizeof(char), LENGTH, fp))>0)
{
if(send(nsockfd, sdbuf, f_block_sz, 0) < 0)
{
printf("ERROR: Failed to send file %s.\n", f_name);
break;
}
bzero(sdbuf, LENGTH);
}
printf("ok!\n");
success = 1;
close(nsockfd);
printf("[server] connection closed.\n");
while(waitpid(-1, NULL, WNOHANG) > 0);
}
}
}
client.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define PORT 5000
#define LENGTH 512 // Buffer length
int main(int argc, char *argv[])
{
int sockfd; // Socket file descriptor
char revbuf[LENGTH]; // Receiver buffer
struct sockaddr_in remote_addr;
/* Get the Socket file descriptor */
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
printf("ERROR: Failed to obtain Socket Descriptor!\n");
return (0);
}
/* Fill the socket address struct */
remote_addr.sin_family = AF_INET;
remote_addr.sin_port = htons(PORT);
inet_pton(AF_INET, "127.0.0.1", &remote_addr.sin_addr);
bzero(&(remote_addr.sin_zero), 8);
/* Try to connect the remote */
if (connect(sockfd, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr)) == -1)
{
printf ("ERROR: Failed to connect to the host!\n");
return (0);
}
else printf("[client] connected to server at port %d...ok!\n", PORT);
//printf ("OK: Have connected to %s\n",argv[1]);
printf("[client] receive file sent by server to receive.txt...");
char* f_name = "receive.txt";
FILE *fp = fopen(f_name, "a");
if(fp == NULL) printf("File %s cannot be opened.\n", f_name);
else
{
bzero(revbuf, LENGTH);
int f_block_sz = 0;
int success = 0;
while(success == 0)
{
while(f_block_sz = recv(sockfd, revbuf, LENGTH, 0))
{
if(f_block_sz < 0)
{
printf("Receive file error.\n");
break;
}
int write_sz = fwrite(revbuf, sizeof(char), f_block_sz, fp);
if(write_sz < f_block_sz)
{
printf("File write failed.\n");
break;
}
bzero(revbuf, LENGTH);
}
printf("ok!\n");
success = 1;
fclose(fp);
}
}
close (sockfd);
printf("[client] connection lost.\n");
return (0);
}
Thank you very much!
You need to add code to the f_block_sz code. recv() has a few posible return values:
<0 -- Error, error number in errno (errno.h)
0 -- Connection closed
>0 -- Data read, number of bytes
You need to handle the second case. Add this else case:
else if(f_block_sz)
{
break;
}
So that the loop will be broken when the server closes the connection, and your code will print you [client] connection lost and exit.
You have another problem in that your server program is multiprocess and forks every time it gets an incoming connection. The parent stays alive to accept new connections and the child processes the connection. The exit from the child process is not enough to cause the parent to exit as well.
If you only want to process one connection then don't use fork.
If you wish to continue your current setup then you will need to change the child process to use _exit instead of exit and get the parent process to handle the SIGCHLD signal (received when a child process exits).
ie.
#include <signal.h>
void terminate(int signal) {
// close sockfd -- you will need to make it global
// or have terminate alter some global variable that main can monitor to
// detect when it is meant to exit
exit(0); // don't exit if you choose the second option
}
int main() {
signal(SIGCHLD, terminate);
...
}

How to know if the client has terminated in sockets

Suppose, I have a connected socket after writing this code..
if ((sd = accept(socket_d, (struct sockaddr *)&client_addr, &alen)) < 0)
{
perror("accept failed\n");
exit(1);
}
How can I know at the server side that client has exited.
My whole program actually does the following..
Accepts a connection from client
Starts a new thread that reads messages from that particular client and then broadcast this message to all the connected clients.
If you want to see the whole code... In this whole code. I am also struggling with one more problem that whenever I kill a client with Ctrl+C, my server terminates abruptly.. It would be nice if anyone could suggest what the problem is..
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <pthread.h>
/*CONSTANTS*/
#define DEFAULT_PORT 10000
#define LISTEN_QUEUE_LIMIT 6
#define TOTAL_CLIENTS 10
#define CHAR_BUFFER 256
/*GLOBAL VARIABLE*/
int current_client = 0;
int connected_clients[TOTAL_CLIENTS];
extern int errno;
void *client_handler(void * socket_d);
int main(int argc, char *argv[])
{
struct sockaddr_in server_addr;/* structure to hold server's address*/
int socket_d; /* listening socket descriptor */
int port; /* protocol port number */
int option_value; /* needed for setsockopt */
pthread_t tid[TOTAL_CLIENTS];
port = (argc > 1)?atoi(argv[1]):DEFAULT_PORT;
/* Socket Server address structure */
memset((char *)&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET; /* set family to Internet */
server_addr.sin_addr.s_addr = INADDR_ANY; /* set the local IP address */
server_addr.sin_port = htons((u_short)port); /* Set port */
/* Create socket */
if ( (socket_d = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
fprintf(stderr, "socket creation failed\n");
exit(1);
}
/* Make listening socket's port reusable */
if (setsockopt(socket_d, SOL_SOCKET, SO_REUSEADDR, (char *)&option_value,
sizeof(option_value)) < 0) {
fprintf(stderr, "setsockopt failure\n");
exit(1);
}
/* Bind a local address to the socket */
if (bind(socket_d, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
fprintf(stderr, "bind failed\n");
exit(1);
}
/* Specify size of request queue */
if (listen(socket_d, LISTEN_QUEUE_LIMIT) < 0) {
fprintf(stderr, "listen failed\n");
exit(1);
}
memset(connected_clients,0,sizeof(int)*TOTAL_CLIENTS);
for (;;)
{
struct sockaddr_in client_addr; /* structure to hold client's address*/
int alen = sizeof(client_addr); /* length of address */
int sd; /* connected socket descriptor */
if ((sd = accept(socket_d, (struct sockaddr *)&client_addr, &alen)) < 0)
{
perror("accept failed\n");
exit(1);
}
else printf("\n I got a connection from (%s , %d)\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
if (pthread_create(&tid[current_client],NULL,(void *)client_handler,(void *)sd) != 0)
{
perror("pthread_create error");
continue;
}
connected_clients[current_client]=sd;
current_client++; /*Incrementing Client number*/
}
return 0;
}
void *client_handler(void *connected_socket)
{
int sd;
sd = (int)connected_socket;
for ( ; ; )
{
ssize_t n;
char buffer[CHAR_BUFFER];
for ( ; ; )
{
if (n = read(sd, buffer, sizeof(char)*CHAR_BUFFER) == -1)
{
perror("Error reading from client");
pthread_exit(1);
}
int i=0;
for (i=0;i<current_client;i++)
{
if (write(connected_clients[i],buffer,sizeof(char)*CHAR_BUFFER) == -1)
perror("Error sending messages to a client while multicasting");
}
}
}
}
My client side is this (Maye be irrelevant while answering my question)
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
void error(char *msg)
{
perror(msg);
exit(0);
}
void *listen_for_message(void * fd)
{
int sockfd = (int)fd;
int n;
char buffer[256];
bzero(buffer,256);
printf("YOUR MESSAGE: ");
fflush(stdout);
while (1)
{
n = read(sockfd,buffer,256);
if (n < 0)
error("ERROR reading from socket");
if (n == 0) pthread_exit(1);
printf("\nMESSAGE BROADCAST: %sYOUR MESSAGE: ",buffer);
fflush(stdout);
}
}
int main(int argc, char *argv[])
{
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
pthread_t read_message;
char buffer[256];
if (argc < 3) {
fprintf(stderr,"usage %s hostname port\n", argv[0]);
exit(0);
}
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,&serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
bzero(buffer,256);
if (pthread_create(&read_message,NULL,(void *)listen_for_message,(void *)sockfd) !=0 )
{
perror("error creating thread");
}
while (1)
{
fgets(buffer,255,stdin);
n = write(sockfd,buffer,256);
if (n < 0)
error("ERROR writing to socket");
bzero(buffer,256);
}
return 0;
}
After accepting the connection, your recv() on the socket will return 0 or -1 in special cases.
Excerpt from recv(3) man page:
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.
So, if your client exited gracefully, you will get 0 from recv() at some point. If the connection was somehow lost, you may also get -1 and checking for appropriate errno would tell you if the connection was lost of some other error occured. See more details at recv(3) man page.
Edit:
I see that you are using read(). Still, the same rules as with recv() apply.
Your server can also fail when trying to write() to your clients. If your client disconnects write() will return -1 and the errno would probably be set to EPIPE. Also, SIGPIPE signal will be send to you process and kill him if you do not block/ignore this signal. And you don't as I see and this is why your server terminates when client presses Ctrl-C. Ctrl-C terminates client, therefore closes client socket and makes your server's write() fail.
See mark4o's answer for nice detailed explanation of what else might go wrong.
If the client program exits, then the OS on the client will close its end of the socket. When you call recv() it will return 0, or -1 with errno ECONNRESET if a TCP RST has been received (e.g. because you attempted to send data after the client had closed). If the whole client machine goes down, or the network becomes disconnected, then in that case you may not receive anything if the server is not trying to send anything; if that is important to detect, you can either send some data periodically, or set the SO_KEEPALIVE socket option using setsockopt() to force it to send a packet with no data after long periods (hours) of inactivity. When no acknowledgment is received, recv() will then return -1 with errno ETIMEDOUT or another error if more specific information is available.
In addition, if you attempt to send data on a socket that has been disconnected, by default the SIGPIPE signal will terminate your program. This can be avoided by setting the SIGPIPE signal action to SIG_IGN (ignore), or by using send() with the MSG_NOSIGNAL flag on systems that support it (Linux).

Resources