I have a simple program that listens to a socket. Everything goes fine except when the connection is lost in while(1) cycle. In this case the program falls into read from socket for many times without result. How can I detect a disconnected client in while(1) cycle?
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include<string.h>
void printHex(char * bts )
{
char *s = bts;
int i=0;
do
{
printf("%02X ", (unsigned char ) *bts);
} while (* ++bts !=0);
printf("%s\n",s);
}
int main()
{
char str[100];
int listen_fd, comm_fd;
struct sockaddr_in servaddr;
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
bzero( &servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htons(INADDR_ANY);
servaddr.sin_port = htons(22000);
printf("binding\n");
bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));
printf("listening\n");
listen(listen_fd, 10);
printf("accepting\n");
comm_fd = accept(listen_fd, (struct sockaddr*) NULL, NULL);
printf("accep done\n");
int cn =0;
while(1)
{
bzero( str, 100);
printf("will read\n");
int br= read(comm_fd,str,100);
printf("read done\n");
if (br>0)
{
printHex(str);
}
}
}
Change:
if (br>0)
{
printHex(str);
}
To:
if (br<=0) break;
printHex(str);
Also, your code mishandles the case where the first byte is zero. And you can't avoid this case because TCP does not preserve application message boundaries. You should just pass br to printHex so it will know how many characters to print.
You need to check the result of your read(). If the connection is closed you'll get a return-code for that.
From the manual page:
On error, -1 is returned, and errno is set appropriately.
Related
I'm trying to learn UDP on C.
My goal is to send a message in console, in the client consol to the server, and sending the exact same message from the server to the client.
When I send a message from client to server, I do receive it, but the opposit is not working, and the waiting is infinite.
I don't have any problem in console.
The weird thing is that i'm using the exact same methode to send both messages.
Here's my client, Thanks to everyone helping me :)
#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>
#define PORT 8080
#define BUFSIZE 4096
// Driver code
int main(int argc, char *argv[]) {
char buffer[BUFSIZE];
struct sockaddr_in servaddr, cliaddr;
int len, n;
char *adresse= argv[1];
if (argc<1){
perror("nb args not enough");
exit(EXIT_FAILURE);
}
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr(adresse);
servaddr.sin_port = htons(PORT);
// Socket()
int udp_server = socket(AF_INET, SOCK_DGRAM, 0) ;
if(udp_server<0){
perror("socket creation failed \n");
exit(EXIT_FAILURE);
}
// Bind())
int errBind = bind(udp_server, (const struct sockaddr *)&servaddr, sizeof(servaddr));
if(errBind<0){
perror("errBind \n" );
exit(EXIT_FAILURE);
}
// recvfrom()
n = recvfrom(udp_server, (char *)buffer, BUFSIZE,0, ( struct sockaddr *) &cliaddr,&len);
if (n<0){
perror("recvfrom error\n" );
exit(EXIT_FAILURE);
}
buffer[n] = '\0';
printf("CLIENT: %s\n", buffer);
char *message ="caca";
sendto(udp_server, (const char *)message, strlen(message),
0, (const struct sockaddr *) &cliaddr,
len);
close(udp_server);
//////////////////////////This part below is never reached
printf("end");
return 0;
}
Also here's my server:
#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>
#define PORT 8080
#define BUFSIZE 4096
// Driver code
int main(int argc, char *argv[]) {
char buffer[BUFSIZE];
// char *message = "AAAAAAAAAAAAAAAAAA";
struct sockaddr_in servaddr, cliaddr;
int len, n;
char *adresse= argv[1];
if (argc<1){
perror("nombre d'arguments insuffisents, veuillez entrer :\n ./serveur port_serveur \n");
exit(EXIT_FAILURE);
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr(adresse);
// servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(PORT);
// Socket()
int udp_server = socket(AF_INET, SOCK_DGRAM, 0) ;
if(udp_server<0){
perror("socket creation failed \n");
exit(EXIT_FAILURE);
}
// Bind())
int errBind = bind(udp_server, (const struct sockaddr *)&servaddr, sizeof(servaddr));
if(errBind<0){
perror("errBind \n" );
exit(EXIT_FAILURE);
}
// recvfrom()
n = recvfrom(udp_server, (char *)buffer, BUFSIZE,0, ( struct sockaddr *) &cliaddr,&len);
if (n<0){
perror("recvfrom error\n" );
exit(EXIT_FAILURE);
}
buffer[n] = '\0';
printf("CLIENT: %s\n", buffer);
int l = sendto(udp_server, (const char *)buffer, strlen(buffer),
0, (const struct sockaddr *) &servaddr,
sizeof(servaddr));
close(udp_server);
printf("end");
//////////////// This is reached
return 0;
}
There are several issues. The main issue is that both the client and server first tries to receive, then send. Thus they cannot both receive the message from the other party. Also, the client need not explicitly bind the socket.
In principle, the client must know the server address, but the server does not know the client address. Hence, the flow of communication must be that the client first sends a message to the server which will make the client known to the server. The server can then send a message to the address of the client.
In summary, the server should:
Create socket
Bind socket
Wait for message (recvfrom())
Send message to sender of the received message (sendto())
Close socket
The client should:
Create socket
Send message to the server (sendto())
Wait for message (recvfrom())
Close socket
I am working on socket with C, and needs to pass command line argument from the client to the server. The server then needs to switch the cases of the sting and send it back to the client. I am stuck at passing the command line argument to the server and then sending it back after switching the case. Here is what I have so far:
#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>
#define PORT 10291
#define MAXLINE 9999
// Client side code
int main(int argc, char *argv[])
{
int sockfd;
char buffer[MAXLINE];
char clientMsg;
struct sockaddr_in servaddr;
// Creating socket file descriptor
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket creation failed");
exit(EXIT_FAILURE);
}
memset(&servaddr, 0, sizeof(servaddr));
// Filling server information
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
servaddr.sin_addr.s_addr = INADDR_ANY;
//Connect to the Server
connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
printf("Connected to the Server. \n");
int n, len;
// Getting Input From Client
/*
printf("Please Enter Your Message: ");
scanf("%s", &clientMsg);
*/
if (argc == 2)
{
for (int i = 0; argc; i++)
{
// send(sockfd, &argv[i], 10000, 0);
sendto(sockfd, (const char *) &clientMsg, strlen(&clientMsg),
MSG_CONFIRM, (const struct sockaddr *) &servaddr,
sizeof(servaddr));
}
printf("Message sent to server. \n");
}
else
{
printf("Error: please enter the correct number of arguments. \n");
close(sockfd);
printf("Disconnected from the server. \n");
exit(1);
}
/*
// Sending message to server
sendto(sockfd, (const char *) &clientMsg, strlen(&clientMsg),
MSG_CONFIRM, (const struct sockaddr *) &servaddr,
sizeof(servaddr));
printf("Message sent to server. \n");
*/
// Receive message from server
n = recvfrom(sockfd, (char*) buffer, MAXLINE,
MSG_WAITALL, (struct sockaddr *) &servaddr, &len);
buffer[n] = '\0';
printf("Message Received From Server: %s\n", buffer);
//Disconnet from the Server
close(sockfd);
printf("Disconneted from the Server. \n");
return 0;
}
#include <stdio.h>
#include <string.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>
#define PORT 10291
#define MAXLINE 9999
// Server Side code
int main(int argc, char *argv[])
{
int sockfd;
char buffer[MAXLINE];
struct sockaddr_in servaddr, cliaddr;
// Creating socket file descriptor
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket creation failed");
exit(EXIT_FAILURE);
}
memset(&servaddr, 0, sizeof(servaddr));
memset(&cliaddr, 0, sizeof(cliaddr));
// Filling server information
servaddr.sin_family = AF_INET; // IPv4
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(PORT);
// Bind the socket with the server address
if (bind(sockfd, (const struct sockaddr *) &servaddr, sizeof(servaddr)) < 0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
int len, n;
len = sizeof(cliaddr); //len is value/resuslt
n = recvfrom(sockfd, (char*) buffer, MAXLINE,
MSG_WAITALL, (struct sockaddr *) &cliaddr, &len);
buffer[n] = '\0';
char c;
while (buffer[c] != '\0')
{
char ch = buffer[c];
if (ch >= 'A' && ch <= 'Z')
buffer[c] = buffer[c] + 32;
else if (ch >= 'a' && ch <= 'z')
buffer[c] = buffer[c] - 32;
c++;
}
//Returning Encrypted String Received By Client
sendto(sockfd, (const char *) buffer, strlen(buffer),
MSG_CONFIRM, (const struct sockaddr *) &cliaddr, len);
close(sockfd);
return 0;
}
Here's my output:
!(https://i.stack.imgur.com/uz7RY.png)
!(https://i.stack.imgur.com/nuSI0.png)
Here is what it should look like:
!( https://i.stack.imgur.com/JnIFn.png)
The server must be able to respond to multiple consecutive client requests and execute until explicitly quit (^-C).
The client should process a single request and then quit on completion.
How should I make it right?
You should start from argv[1], since argv[0] is the program name, not an argument.
for (int i = 1; i < argc; i++) {
sendto(sockfd, argv[i], strlen(argv[i]),
MSG_CONFIRM, (const struct sockaddr *) &servaddr,
sizeof(servaddr));
}
I'm using C to implement a simple client-server retrieval system with Linux socket. I've now successfully connect the remote server, but when I close the connection, the server went down, i.e. the server program stopped.
What should I do avoid this?
here's sample of my code:
server:
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>
int main(void)
{
int optval;
socklen_t optlen = sizeof(optval);
char str[100] = "";
int listen_fd, conn_fd;
struct sockaddr_in servaddr;
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
// check if on
getsockopt(listen_fd, SOL_SOCKET, SO_KEEPALIVE, &optval, &optlen);
printf("keep alive is %s\n", (optval? "ON" : "OFF"));
// set it on
optval = 1;
optlen = sizeof(optval);
setsockopt(listen_fd, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen);
printf("done, check again.\n");
printf("keep alive is %s\n", (optval? "ON" : "OFF"));
bzero( &servaddr, sizeof(servaddr));
// set appropriate protocol and port number (15792)
// the htons() function converts the unsigned short integer
// from host byte order to network byte order.
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htons(INADDR_ANY);
servaddr.sin_port = htons(15792);
// Bind a name to a socket
bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));
// listening for incoming connection
listen(listen_fd, 10);
// accept a connection on a socket
conn_fd = accept(listen_fd, (struct sockaddr*) NULL, NULL);
do
{
// set str to null
bzero(str, 100);
// Read from a file descriptor (linux all)
read(conn_fd,str,100);
// print the received message
// printf("Received: %s\n",str);
if (!strcmp(str, "GET TIME\n"))
{
bzero(str, 100);
time_t clocks;
clocks = time(NULL);
sprintf(str, "%s", ctime(&clocks));
write(conn_fd, str, strlen(str));
//close(conn_fd);
}
else
{
bzero(str, 100);
strcpy(str, "ERROR: No such command.\n");
write(conn_fd, str, strlen(str));
//close(conn_fd);
}
} while (1);
}
client:
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc,char **argv)
{
// declare necessary variables
int sockfd;
char recv[1024] = "";
char command[100] = "";
struct sockaddr_in servaddr;
if (argc != 2)
{
printf("usage: %s <ip address>\n", argv[0]);
exit(EXIT_FAILURE);
}
// create a socket with the appropriate protocol
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("ERROR: Failed create cosket.\n");
exit(EXIT_FAILURE);
}
// Set all the socket structures with null values.
bzero(&servaddr, sizeof servaddr);
// set appropriate protocol and port number (1999)
// The htons() function converts the unsigned short integer
// hostshort from host byte order to network byte order.
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(15792);
// Convert IPv4 and IPv6 addresses from text to binary form
if (inet_pton(AF_INET, argv[1], &(servaddr.sin_addr)) <= 0)
{
printf("ERROR: Wrong ip address.\n");
exit(EXIT_FAILURE);
}
// attempt to connect to a socket
if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
{
printf("ERROR: Failed at connect.\n");
exit(EXIT_FAILURE);
}
else
{
printf("------ connect successfull ------\n");
}
do
{
printf("> ");
fgets(command, 100, stdin);
write(sockfd, command, strlen(command));
if (!strcmp(command, "QUIT\n"))
{
close(sockfd);
break;
}
// print the receive stuff
read(sockfd, recv, sizeof(recv));
fputs(recv, stdout);
bzero(recv, 1024);
} while (1);
}
In your server code, the accept() function must be called in the do-while loop:
// listening for incoming connection
listen(listen_fd, 10);
do
{
// accept a connection on a socket
conn_fd = accept(listen_fd, (struct sockaddr*) NULL, NULL);
...
close(conn_fd);
} while(1);
my question here is, why server ended if I close the connection from
the client.
Because then the blocking read call will return the value 0 indicating the connection was closed, which you promptly ignore. You then try (and fail) to compare the received data (which you have none) to the string and you will attempt to write the error message to the (now disconnected) client which will raise the SIGPIPE error which terminates your application.
– Some programmer dude
I am writing a TCP client in C.
Following several tutorial I wrote my code but it can accept only the first connection to the server.
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h> //inet_addr for INADDR_ANY
#include <string.h> //for splitting (strtok)
#include <pthread.h> //thread library
#include <time.h>
#include <unistd.h> //for function close()
void* SocketHandler(void*);
int main(void) {
//socket parameters
int server_socket_desc;
int clientAddressLength = sizeof(struct sockaddr_in);
struct sockaddr_in server_addr, client_addr;
const unsigned short int PORT_NUMBER = 8963;
server_socket_desc = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (server_socket_desc < -1) {
printf("Could not create socket");
}
puts("Socket created");
//Prepare the sockaddr_in structure
server_addr.sin_family = AF_INET; //it should be always set to AF_INET
//set the server address
server_addr.sin_addr.s_addr = inet_addr("192.168.123.240");
//server_addr.sin_addr.s_addr = inet_addr("31.185.101.35");
//server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
server_addr.sin_port = htons(PORT_NUMBER);
//Bind
if (bind(server_socket_desc, (struct sockaddr *) &server_addr,
sizeof(server_addr)) < 0) {
//print the error message
perror("bind failed. Error");
return 1;
}
puts("bind done");
//Listen
listen(server_socket_desc, 10);
//Accept and incoming connection
puts("Waiting for incoming connections...");
//accept connection from an incoming client
while (1) {
int *temp_socket_desc = (int*) malloc(sizeof(int));
if ((*temp_socket_desc = accept(server_socket_desc,
(struct sockaddr *) &client_addr,
(socklen_t*) &clientAddressLength)) != -1) {
printf("----------\nConnection accepted \n");
sleep(1);
pthread_t thread_id;
int *client_socket_desc = (int*) malloc(sizeof(int));
client_socket_desc = temp_socket_desc;
pthread_create(&thread_id, NULL, &SocketHandler,
(void*) client_socket_desc);
//if thread has not terminated, pthread_detach() shall not cause it to terminate
pthread_detach(thread_id);
puts("handler assigned");
} else
puts("connection refused");
}
close(server_socket_desc);
//mysql_close(mysql_conn);
return 0;
}
/*
* This will handle connection for each client
* */
void* SocketHandler(void* lp) {
int *csock = (int*) lp;
char buffer[128];
int buffer_len = 128;
int bytecount;
memset(buffer, 0, buffer_len);
if ((bytecount = read(*csock, buffer, buffer_len) == -1)) {
fprintf(stderr, "Error receiving data\n");
close(*csock);
return 0;
}
printf("Received bytes %d\nReceived string \"%s\"\n", bytecount, buffer);
close(*csock);
free(csock);
puts("exiting thread");
//pthread_exit(0);
return 0;
}
I temporally solved the problem inserting a sleep() after the while loop but it is a very bad solution.
Can somebody explain me why the code does'n work without the sleep?
There is a problem in handling of client_socket_desc:
You allocate it only once. All threads will get the same pointer.
So later accepts will override socket descriptors value of earlier threads.
Try the following change, for allocating own memory block for each thread:
int fd = accept( server_socket_desc, (struct sockaddr *) &client_addr, (socklen_t*)
&clientAddressLength)
if ( fd != -1 )
{
pthread_t thread_id;
int *client_socket_desc = malloc(sizeof(int));
*client_socket_desc = fd;
pthread_create(&thread_id, NULL, &SocketHandler,(void*) client_socket_desc);
...
Or course you must add error handlings for malloc and pthread_create.
And also free the allocated memory when not needed anymore.
I don't understood why there is the following code in the while loop:
if(send(*client_socket_desc,buffer,1,MSG_NOSIGNAL)>0)
{
puts("closing client socket");
close(*client_socket_desc);
}
Close client sockets in client handler threads.
I am working through examples in UNIX Network Programming and I've adapted "daytimeclientserv.c" into this code here. The server sends the date/time string to the client as expected except for the very first request it receives upon starting up. When I first run the server program (on another computer in the LAN) it creates the listening socket, binds it and then waits for connections. Upon receiving the first request it prints the date/time string to its own stdout (terminal) instead of to the socket and the client program hangs forever waiting. However, all subsequent requests are sent to the clients correctly. Using gdb, I noticed that connfd is always set to zero. It is set to zero on the first request and also on all future ones.
I also have a few other questions related to this:
if the server listens on one socket (listenfd) and then reconnects on another (connfd) with connect(), how does the client deal with the change of socket? It was my understanding that a socket is uniquely identified by four parts: servIPaddr, servPort, clientIPaddr, clientPort
how can i run the server (on linux) without being root
how can i cleanly close the listening socket, so that i can use it again. I get a bind error if I quit the server program with SIGINT (Ctrl-C). So far I've been using gdb, and using a "call close(listenfd)" to manually call the function. But is there a way to do this if I am not using gdb (ie. debugging the client application only).
Any help is greatly appreciated.
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#define BUFFER 80
int main(int argc, char **argv) {
int listenfd, connfd;
char buf[BUFFER];
struct sockaddr_in servaddr;
time_t ticks;
struct sockaddr *ptr;
char *ret;
if ( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket error");
return 1;
}
memset(&servaddr, 0, sizeof(servaddr));
memset(buf, 0, BUFFER);
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(13);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
ptr = (struct sockaddr*) &servaddr;
if ( bind(listenfd, ptr ,sizeof(servaddr)) < 0) {
perror("bind error");
return 2;
}
if ( listen(listenfd, 128) < 0) {
perror("listen error");
return 3;
}
ptr = NULL;
while ( 1 ) {
if ( connfd = accept(listenfd, ptr, NULL) < 0) {
perror("accept error");
return 4;
} else {
ticks = time(NULL);
ret = ctime(&ticks);
sprintf(buf, "%.24s\n", ret);
if ( write(connfd, buf, strlen(buf)) < 0) {
perror("write error");
close(connfd);
}
}
return 0;
}
Here was my hunch: On a terminal (tty), stdout and stdin are the same physical device. Therefore writing to filedescriptor 0 (stdin) might actually work and result in terminal output.
You need parentheses around this
if ( connfd = accept(listenfd, ptr, NULL) < 0) {
Like so
if ( (connfd = accept(listenfd, ptr, NULL)) < 0) {
Or connfd will be assigned '0'
Update Just tested this, and this is indeed the culprit. Next time, compile with gcc -Wall and the compiler would have told you this (and several other issues of good form/style). That way, you won't have to rely on having the hunch to find the error.
Fixed version:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#define BUFFER 80
int main(int argc, char **argv) {
int listenfd, connfd;
char buf[BUFFER];
struct sockaddr_in servaddr;
time_t ticks;
struct sockaddr *ptr;
char *ret;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
if ( listenfd < 0 ) {
perror("socket error");
return 1;
}
memset(&servaddr, 0, sizeof(servaddr));
memset(buf, 0, BUFFER);
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(13);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
ptr = (struct sockaddr*) &servaddr;
if ( bind(listenfd, ptr ,sizeof(servaddr) ) < 0) {
perror("bind error");
return 2;
}
if ( listen(listenfd, 128) < 0 ) {
perror("listen error");
return 3;
}
ptr = NULL;
while ( 1 ) {
connfd = accept(listenfd, ptr, NULL);
if ( connfd < 0 ) {
perror("accept error");
return 4;
} else {
ticks = time(NULL);
ret = ctime(&ticks);
sprintf(buf, "%.24s\n", ret);
if ( write(connfd, buf, strlen(buf)) < 0) {
perror("write error");
close(connfd);
}
}
}
return 0;
}