TCP client/server printing extra strings - c

I am trying to make a program with a server and multiple clients can connect to that server through the predefined port nummber. By the way, this is TCP in C. I have the following server code below:
SERVER CODE:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
void *connection_handler(void *);
int main(int argc , char *argv[])
{
int listenfd , connfd , c , *new_sock;
struct sockaddr_in servaddr , cliaddr;
listenfd = socket(PF_INET , SOCK_STREAM , 0);
if (listenfd == -1)
puts("SOCKET CREATION ERROR!");
puts("Socket created");
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(54321);
bind(listenfd, (struct sockaddr*) &servaddr, sizeof(servaddr) );
listen(listenfd,2);;
c = sizeof(struct sockaddr_in);
while( (connfd = accept(listenfd, (struct sockaddr *)&cliaddr, (socklen_t*)&c)) ){
puts("Connection accepted");
pthread_t sniffer_thread;
new_sock = malloc(1);
*new_sock = connfd;
if( pthread_create( &sniffer_thread , NULL , connection_handler , (void*) new_sock) < 0)
{
perror("Thread Error Connection");
return 1;
}
puts("Handler assigned");
}
if (connfd < 0)
{
perror("accept failed");
return 1;
}
return 0;
}
void *connection_handler(void *socket_desc)
{
int sock = *(int*)socket_desc;
int read_size;
char client_message[51]="";
while( (read_size = recv(sock , client_message , 50, 0)) > 0 )
{
printf("%s",client_message);
}
if(read_size == 0)
{
puts("Client disconnected");
fflush(stdout);
}
free(socket_desc);
return 0;
}
CLIENT CODE:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr;
socklen_t len = sizeof(servaddr);
char mesg[1024];
if(argc!=2){
printf("Usage: %s <ip_addr>\n",argv[0]);
exit(1);
}
sockfd = socket(PF_INET,SOCK_STREAM,0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(54321);
inet_pton(AF_INET,argv[1],&servaddr.sin_addr);
connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
while(1){
fgets(mesg,sizeof(mesg),stdin);
sendto(sockfd,mesg,strlen(mesg),0,(const struct sockaddr *)&servaddr,len);
}
close(sockfd);
return 0;
}
I get the following output:
Socket created
Connection accepted
Handler assigned
Hello There!
What could be the problem?
I don't know?
the problem?
Hey!
't know?
the problem?
I typed in the following strings in the client terminal:
Hello There!
What could be the problem?
I don't know?
Hey!
The problem is when I typed the third string, the output is the third string with some parts of the second string still appearing. What could be the problem? Thanks!

TCP is stream oriented.
You can not expect that write() writes as much data as you told it to write, as well as you can not expect that read() reads as much data as you told it ro read.
This both put together means that to transfer N bytes via a socket the number of calls to read() does not necessarily needs to match the number of calls to write().
And following this conclusion the only thing the reader could know is how much it read from the moment on it was created.
The only two synchronisation points between reader and writer are the creation and the shutdown of the connection. The period one can call a session.
So if one wants to transfer multiple blocks of data having different sizes unknown to the reader during one session one is in the need to establish additional synchronisation points during the session, that make the read detect that a full block had been received.
Doing so is implementing some sort of protocol.
There are endless possiblities how the protcol could look like. The detailed design of the protocol depends on the use cases which shall be covered by the application.
Assuming only text data shall be transfered a simple protocol could be to terminate each data block by a \n.
The writer loops around write() until all data is sent and finally sends a \n.
The reader loops around read() until a \n had been received.

C strings are null terminated. You're not sending the zero byte that would terminate your string in your recieving buffer, so your printf will print out all characters it find until it reaches some zero byte. strlen returns length of string in number of characters, but without counting the zero byte at the end.
Try to change line in your client:
sendto(sockfd,mesg,strlen(mesg),0,(const struct sockaddr *)&servaddr,len);
Into:
sendto(sockfd,mesg,1+strlen(mesg),0,(const struct sockaddr *)&servaddr,len);

Related

Creating Multiple Client and One Server for UDP application using select() system call with C

Help me to correct this program I want to create a server that can run indefinitely and can serve many clients and for that, I am using a select system call for UDP (User Datagram Protocol) application.
My issue is that this code is running for multiple clients in a different session that means after running for one client it stops and again when I start the server again then it can serve another client also.
I want my code to work indefinitely in one session only and serve as many clients as I want.
Server Code:-
'''
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define port1 8080
#define MAXN 1024
#define TRUE 1
int main(){
int sockfd,sockfd1;
struct sockaddr_in servaddr,cliaddr;
char buffer[MAXN];
char buff[MAXN];
int max_clients=2,valread,new_socket;
char *hello = "Hello Client";
char *message = "hiiii Server";
struct timeval timeout;
timeout.tv_sec = 20;
timeout.tv_usec = 0;
//create socket 2
sockfd = socket(AF_INET, SOCK_DGRAM,0);
if(sockfd<0){
perror("Error Creating Socket0");
exit(1);
}
//memset(&servaddr, 0, sizeof(servaddr));
//memset(&cliaddr, 0, sizeof(cliaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(port1);
servaddr.sin_addr.s_addr = INADDR_ANY;
if(bind(sockfd, (const *)&servaddr, sizeof(servaddr))<0){
perror("Error in binding0 ");
exit(1);
}
//Use Select......
//I have created 2 socket having file deescriptor sockfd and sockfd1
int s;
int client_socket[2]={0,0};
fd_set readfds;
while(){
FD_ZERO(&readfds);
FD_SET(sockfd,&readfds);
//Let's say sockfd is max_fd
int max_fd = sockfd,sd,activity;
for(int i=0;i<2;i++){
sd = client_socket[i];
if(sd>0){
FD_SET(sd,&readfds);
}
if(sd>max_fd)
max_fd = sd;
}
activity = select( max_fd + 1 , &readfds , NULL , NULL , &timeout);
if ((activity < 0))
{
printf("select error");
}
int addrlen = sizeof(servaddr);
//If something happened on the master socket ,
//then its an incoming connection
if (FD_ISSET(sockfd, &readfds))
{
//inform user of socket number - used in send and receive commands
printf("New connection , socket fd is %d , ip is : %s , port : %d\n " , new_socket , inet_ntoa(servaddr.sin_addr) , ntohs
(servaddr.sin_port));
//send new connection greeting message
if( send(new_socket, message, strlen(message), 0) != strlen(message) )
{
perror("send");
}
puts("Welcome message sent successfully");
//add new socket to array of sockets
for (int i = 0; i < max_clients; i++)
{
//if position is empty
if( client_socket[i] == 0 )
{
client_socket[i] = new_socket;
printf("Adding to list of sockets as %d\n" , i);
break;
}
}
}
//else its some IO operation on some other socket
for (int i = 0; i < max_clients; i++)
{
sd = client_socket[i];
if (FD_ISSET( sd , &readfds))
{
//Check if it was for closing , and also read the
//incoming message
if ((valread = read( sd , buffer, 1024)) == 0)
{
//Somebody disconnected , get his details and print
getpeername(sd , (struct sockaddr*)&servaddr , \
(socklen_t*)&addrlen);
printf("Host disconnected , ip %s , port %d \n" ,
inet_ntoa(servaddr.sin_addr) , ntohs(servaddr.sin_port));
//Close the socket and mark as 0 in list for reuse
//close( sd );
client_socket[i] = 0;
}
//Echo back the message that came in
else
{
//set the string terminating NULL byte on the end
//of the data read
buffer[valread] = '\0';
send(sd , buffer , strlen(buffer) , 0 );
}
}
}
}
return 0;
}
'''
This is one of the Client Code and this code is running :-
'''
#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 MAXN 1024
// Driver code
int main() {
int sockfd;
char buffer[MAXN];
char *hello = "Hello from Multipleclient";
struct sockaddr_in servaddr;
// Creating socket file descriptor
if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
perror("Error in socket creation");
exit(1);
}
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;
int n, len;
sendto(sockfd, (const char *)hello, strlen(hello),
MSG_CONFIRM, (const struct sockaddr *) &servaddr,
sizeof(servaddr));
printf("Hello message sent.\n");
n = recvfrom(sockfd, (char *)buffer, MAXN,
MSG_WAITALL, (struct sockaddr *) &servaddr,
&len);
buffer[n] = '\0';
printf("Server : %s\n", buffer);
close(sockfd);
return 0;
}
Some minor things to start with:
In the client code, you do not initialize len before passing it to recvfrom. Also, it is of the wrong type (int instead of socklen_t). This can be corrected by defining len as socklen_t len = sizeof(servaddr); However, since you do not use the length or address anywhere, you can just pass in NULL for both. Also, UDP does not support MSG_WAITALL, so pass 0 instead for the flags. recvfrom(sockfd, (char *)buffer, MAXN, 0, NULL, NULL).
In the client code, you fill in the server IP address as IPADDR_ANY, i.e. 0.0.0.0, which is only valid when calling bind. You are calling sendto. When specifying a destination address, you probably want IPADDR_LOOPBACK for the local computer.
In the server code, the main while() loop is missing a condition inside the parenthesis, so the code does not even compile. You probably want while(1) for an infinite loop.
In the server code, in the call to bind, you are casting to the wrong type. (const *) means (const int *), but you want (const struct sockaddr *).
The biggest problem:
Based on the comments and code in the server code, you seem to think that UDP communication has persistent connections, and try to save client_socket values for these. However, UDP does not have persistent connection. There is no such thing as a client socket in this context. select does not tell you that a new "connection" is ready. Instead, it tells you that data has been received on your one and only UDP socket (sockfd). This is entirely unlike TCP, where you accept a connection that lasts until one side terminates it.
From the comments in the server code, it seems that you intend for clients to have persistent state in the server, at least enough to be recognized when they send more datagrams (otherwise they would always get the welcome message).
A possible way to make this work is the following:
// create and bind a UDP socket as you already do;
// initialize and empty list of clients;
while(1) {
struct sockaddr_in cliaddr;
socklen_t cliaddr_len = sizeof(cliaddr);
recvfrom(sockfd, buffer, bufferlen, /*flags*/ 0, (struct sockaddr *)&cliaddr, &cliaddr_len);
// check whether cliaddr is in your list;
if (!is_in_list) {
// this is a new client
// add to list of clients;
// send welcome message;
}
// do something else, maybe echo back the buffer contents;
}
You will notice that the code does not actually use select anymore. select is unnecessary if you have nothing to do while waiting, and you only listen to one socket. If you are doing other stuff not shown in the question, you can add the select back at the top of the infinite loop, and only handle the UDP socket if sockfd is set in the readfds from select.
Also note that the client cannot actually receive answers from the server, since there is no persistent connection, and the client has not passed any socket to bind. And also note that UDP messages may get lost without warning, and you should make sure your code can deal with that. It seems that this client-server-strategy would be easier to implement using TCP.
As a side note, it is strongly recommended to enable warnings in your compiler. That would have caught the wrong type for the address length variables, as well as told you that new_socket is used but never set. It is polite to fix all warnings before posting a question, unless of course the question is about the warning.

How to emulate PUB/SUB with unix sockets (AF_UNIX, SOCK_DGRAM)?

I am struggling to make this simple communication working.
I made it with zmq in less than five minutes.
Doing it with UNIX sockets is a pain (obviously because of my lack of confidence).
This is the server:
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "streamsocket.h"
char *socket_path = "/tmp/stream";
int socket_fd=0;
struct sockaddr_un addr;
int main(){
socket_setup();
while(1){
socket_sendstr("a");
sleep(1);
}
}
void socket_setup(){
int rc;
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, socket_path);
if ( (socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) {
perror("socket error");
exit(-1);
}
rc=bind(socket_fd, (struct sockaddr *) &addr, sizeof(addr));
if(rc<0){
perror("bind error");
exit(-2);
}
}
int socket_sendstr(char* buffer) {
int len=strlen(buffer);
// corrected after suggestion in answer below (rc->len)
// int rc=write(socket_fd, buffer, rc);
int rc=write(socket_fd, buffer, len);
if (rc != len) {
if (rc > 0) fprintf(stderr,"partial write");
else {
perror("write error");
//exit(-1);
}
}
}
And this is the client:
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(){
char * server_filename = "/tmp/stream";
char * client_filename = "/tmp/stream-client";
struct sockaddr_un server_addr;
struct sockaddr_un client_addr;
int rc;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sun_family = AF_UNIX;
strncpy(server_addr.sun_path, server_filename, 104);
memset(&client_addr, 0, sizeof(client_addr));
client_addr.sun_family = AF_UNIX;
strncpy(client_addr.sun_path, client_filename, 104);
// get socket
int sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);
// bind client to client_filename
rc = bind(sockfd, (struct sockaddr *) &client_addr, sizeof(client_addr));
if(rc==-1) perror("bind error");
// connect client to server_filename
rc = connect(sockfd, (struct sockaddr *) &server_addr, sizeof(server_addr));
if(rc==-1) perror("connect error");
char buf[1024];
int bytes=0;
while(bytes = read(sockfd, buf, sizeof(buf))){
printf("%s\n",buf);
}
close(sockfd);
}
What I am doing wrong?
At the moment the client does not print anything.
EDIT1: correct wrong "rc" in server write( , ,rc) to write( , ,len)
EDIT2: as client does not work socat either:
socat UNIX-CLIENT:/tmp/stream -
so I think that the problem could be in the server.
int len=strlen(buffer);
int rc=write(socket_fd, buffer, rc);
Doesn't write expects to get as third parameter the length ;
You misunderstand how datagram sockets work, and this is not local to Unix sockets -- you'd have the same problem with UDP.
Datagram sockets are entirely connectionless. A connect() on a datagram socket doesn't actually make any connection, it just sets a default destination for packets sent on the socket. It's just for convenience so that you can use send instead of sendto in the case where you always send to the same address.
You can make the server reply to a particular client if the client sends a packet to the server first, in which case you can reply, using sendto, to the same address that you got from recvfrom. If you actually want to make a connection between the client and the server, however, you'll need to use either a stream socket or a seqpacket socket instead. In that case, you will also need to ensure you're doing the proper listen/accept sequence in the server as well.
In fact, I would, if anything, be surprised if your server doesn't print errors when it tries to send. It should be saying write error: Transport endpoint is not connected.

unexpected multithreaded server reaction - C

I'm working on a multithreaded server/client. The problem I have is that the server handling sometimes looks a little bit various. The message, which is send back is always correct, but the message the server prints out is a little bit weird. If it is a short word like "hello" everything works. If it is a long word or there are spaces in the string like "Binominalkoeffizient" the out-printed serversided message is:
Binomina
lkoeffiz
ient
fiz
Any idea where my mistake is?
PS: The server reaction is the same when I use telnet!
Server-Main:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include "server.h"
int main(int argc, const char * argv[]) {
int sock;
struct sockaddr_in server;
sock = socket(AF_INET, SOCK_STREAM, 0);
socketStatusCheck(sock);
puts("[*] Starting Server ...");
puts("[*] Initialize Server ...");
initializeServer(&server, 8888);
bindServerToAddress(sock, server);
puts("[*] Waiting for incomming connections ... ");
puts("");
listen(sock, 3);
connectionSwitch(sock);
close(sock);
return 0;
}
Server-File
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include "server.h"
void socketStatusCheck(int sock) {
if (sock == -1) {
perror("Error creating the socket: ");
exit(0);
}
}
void initializeServer(struct sockaddr_in *server, int port) {
server->sin_family = AF_INET;
server->sin_addr.s_addr = INADDR_ANY;
server->sin_port = htons(port);
}
void bindServerToAddress(int sock, struct sockaddr_in server) {
if (bind(sock, (struct sockaddr*) &server, sizeof(server)) < 0) {
perror("Error binding port: ");
}
}
void connectionSwitch(int sock) {
int nsock, lenbuf;
struct sockaddr_in client;
pthread_t pid = NULL;
lenbuf = sizeof(struct sockaddr_in);
while ((nsock = accept(sock, (struct sockaddr*) &client, (socklen_t*) &lenbuf))) {
puts("Client connected!");
if (pthread_create(&pid, NULL, connectionHandler, (void*) &nsock))
perror("Error creating thread: ");
}
if (nsock < 0) {
perror("Error accepting incomming client: ");
}
pthread_exit(pid);
}
void *connectionHandler(void *sockptr) {
int sock = *(int*) sockptr;
long isConnected;
char *smessage, *recvmessage;
smessage = "Hello! I am the server you just connected! \n";
write(sock, smessage, strlen(smessage));
recvmessage = malloc(5000 * sizeof(char)); // while ((isConnected = recv(sock, recvmessage, sizeof(recvmessage), 0)) > 0)
while ((isConnected = recv(sock, recvmessage, sizeof(recvmessage), 0)) > 0) {
//write(sock, recvmessage, sizeof(recvmessage));
send(sock, recvmessage, sizeof(recvmessage), 0);
puts(recvmessage);
}
if (isConnected == 0) {
perror("Client disconnected: ");
fflush(stdout);
}
free(recvmessage); recvmessage = NULL;
return 0;
}
This really has nothing to do with multithreading, and everything to do with the nature of SOCK_STREAM sockets.
Stream sockets are, as the name suggests, a stream of bytes; they do not preserve message boundaries such that what is sent with one call to send is received with one call to recv. A single send may be broken up across multiple recv calls, or multiple send calls may be coalesced into a single recv, or both. They do guarantee order, in that the bytes will be received in the same order they are sent.
You'll need to implement your own record marking, perhaps by inserting \0 characters to delimit words, or by using length prefixes.
This is normal behavior. When you use send you don't know how many bytes will be sent. It may happen that all the words , characters are sent.However there are ways to solve this problem. One way is to write a simple header to the string you send , which contains the length of the string you are sending . So you know when the string is ending . For example you can use a thread to look continuously for messages and because the header contains the length of the string you know when to print a \n.The behavior of the send cannot be altered , because it is the Kernel , that is doing this .
In addition to what the other answers say already:
Your code specifically asks to read 8 bytes at a time. recvmessage is a pointer, and pointers are 8 bytes on your system, so sizeof(recvmessage) is 8.

Socket arbitrarily connects - or doesnt

I'm working on a university project, in which I have to connect a raspberry pi to an Android smartphone to control 2 motors.
We are new to socket programming, so we started out with an example we found on wikibooks and tried to modify in to our needs. We're now facing the problem, that the connection between server and client is very arbitrary and unstable, sometimes connecting, and after a brief disconnect doesnt connect again. The weird thing (for me) is, that after we edit the code above the part responsible for connection:
/* bind serv information to mysocket */
bind(mysocket, (struct sockaddr *)&serv, sizeof(struct sockaddr));
/* start listening, allowing a queue of up to 2 pending connection */
listen(mysocket, 2);
consocket = accept(mysocket, (struct sockaddr *)&dest, &socksize);
like inserting in a printf, the next time we launch the programm, everthing does work, sometimes two or three times, and then it just stops connecting.
I've searched all over google and so for a similar problem, but I haven't found an equivalent, so I turn to you directly now.
This is code for our server running on the raspberry pi, which also serves as a network hotspot:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <bcm2835.h>
#define PORTNUM 5298
#define MAXRCVLEN 1000
#define PIN9 RPI_GPIO_P1_21
#define PIN10 RPI_GPIO_P1_19
#define PIN11 RPI_GPIO_P1_23
#define PIN22 RPI_GPIO_P1_15
int setpins();
int forward();
int backward();
int main(int argc, char *argv[])
{
char msg[] = "Connected!\n";
char testchar[] = "stillthere?";
char quitstring[] = "quit";
char *recbuf;
int qflag = 0;
int lflag = 0;
int mysocket, consocket, len; /* socket used to listen for incoming connections */
struct sockaddr_in dest; /* socket info about the machine connecting to us */
struct sockaddr_in serv; /* socket info about our server */
socklen_t socksize = sizeof(struct sockaddr_in);
memset(&serv, 0, sizeof(serv)); /* zero the struct before filling the fields */
serv.sin_family = AF_INET; /* set the type of connection to TCP/IP */
serv.sin_addr.s_addr = htonl(INADDR_ANY); /* set our address to any interface */
serv.sin_port = htons(PORTNUM); /* set the server port number */
mysocket = socket(AF_INET, SOCK_STREAM, 0);
/* bind serv information to mysocket */
bind(mysocket, (struct sockaddr *)&serv, sizeof(struct sockaddr));
/* start listening, allowing a queue of up to 2 pending connection */
listen(mysocket, 2);
consocket = accept(mysocket, (struct sockaddr *)&dest, &socksize);
if (!bcm2835_init()) return 1;
setpins();
while(consocket)
{
printf("Incoming connection from %s - sending welcome\n", inet_ntoa(dest.sin_addr));
send(consocket, msg, strlen(msg), 0);
while (!qflag && !lflag) {
// Do something when connection is lost: SO_KEEPALIVE?
// if (!send(consocket,testchar, strlen(testchar), 0)) lflag = 1;
recbuf = malloc (MAXRCVLEN+1);
len = recv(consocket, recbuf, MAXRCVLEN, 0);
recbuf[len] = '\0';
if (len > 0) printf("Client sent %s (%d bytes). \n", recbuf, len);
if (recbuf[0] == 'v') forward(); // this function lets our car drive forward
if (recbuf[0] == 'r') backward();// this one backwards ;)
// Leave this loop if the client sends you the quitstring
if (!strcmp (recbuf, quitstring)) qflag = 1;
free(recbuf);
}
if (qflag) break;
listen(mysocket, 1);
consocket = accept(mysocket, (struct sockaddr *)&dest, &socksize);
}
close(consocket);
close(mysocket);
printf("sockets closed\n");
return EXIT_SUCCESS;
}
One line in there
// if (!send(consocket,testchar, strlen(testchar), 0)) lflag = 1;
is our idea to test wether the connection is still up, is this viable?
And this is the client code, thats not in Java yet but in C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define MAXRCVLEN 500
#define PORTNUM 5298
int main(int argc, char *argv[])
{
char buffer[MAXRCVLEN + 1]; /* +1 so we can add null terminator */
int len, mysocket;
struct sockaddr_in dest;
mysocket = socket(AF_INET, SOCK_STREAM, 0);
memset(&dest, 0, sizeof(dest)); /* zero the struct */
dest.sin_family = AF_INET;
dest.sin_addr.s_addr = inet_addr("192.168.42.1"); /* set destination IP number */
dest.sin_port = htons(PORTNUM); /* set destination port number */
do {
connect(mysocket, (struct sockaddr *)&dest, sizeof(struct sockaddr));
len = recv(mysocket, buffer, MAXRCVLEN, 0);
}while(len < 0);
/* We have to null terminate the received data ourselves */
buffer[len] = '\0';
// Received
printf("Received %s (%d bytes).\n", buffer, len);
// send:
char msg[] = " ";
do{
scanf("%s",msg);
printf("Sending Msg to %s \n", inet_ntoa(dest.sin_addr));
send( mysocket, msg, strlen(msg),0);
}while (strcmp(msg,"quit"));
close(mysocket);
return EXIT_SUCCESS;
}
Any ideas what we did wrong?
Thanks in advance!
Unless what you actually, really want to learn is low-level berkeley socket manipulation, I'd suggest you look at libevent or a similar library.
The structure of your main loop is a little unusual. You can clearly only handle one connection at a time, and you don't cope well with any connection attempts that happened while you were servicing a previous connection.
bind(mysocket, (struct sockaddr *)&serv, sizeof(struct sockaddr));
bind can fail, e.g. if another process has recently had the socket open and the OS hasn't finished cleaning up use of the port. You can change this behavior, but you should still check, from die.net's bind manpage
Return Value
On success, zero is returned. On error, -1 is returned, and errno is set appropriately.
so
if(bind(mysocket, (struct sockaddr *)&serv, sizeof(struct sockaddr))) {
perror("bind failed");
exit(1);
}
listen() only needs to be called once, but also needs to be checked
if(listen(mysocket, 2)) {
perror("listen failed");
exit(1);
}
after this, if you are content to do the single-service approach, then you can do the following:
mysocket = socket(AF_INET, SOCK_STREAM, 0);
if(mysocket < 0) {
perror("socket failed");
exit(1);
}
if(bind(mysocket, (struct sockaddr *)&serv, sizeof(struct sockaddr))) {
perror("bind failed");
exit(1);
}
if(listen(mysocket, 2)) {
perror("listen failed");
exit(1);
}
for (;;) {
consocket = accept(mysocket, (struct sockaddr *)&dest, &socksize);
if(consocket < 0) // might return if the connection has already gone away.
continue;
if (!sendGreeting(consocket)) {
// sendGreeting should return -1 if it was unable to send, 0 if successful
while (!readLoop(consocket, recvBuf, MAXRCVLEN))
;
}
close(consocket);
}
readLoop would then be something like:
int readLoop(int socket, char* buffer, size_t bufSize) {
int len = recv(socket, buffer, bufSize);
if (len > 0)
return processBuffer(socket, buffer, len);
if (len < 0 && (errno == EINTR || errno == EAGAIN))
return 0; // do-over
return -1;
}
make sure that processBuffer also returns 0 or -1 accordingly.
As I mentioned above, there are still problems with this approach, but it's not my intent here to teach you everything you need to know about sockets in one pass :) If you want to further develop your socket knowledge, your next stop should be learning about select or poll with non-blocking sockets so that you can host multiple sockets and service them as they become active.
Generally, you should use tcpdump/wireshark to see what packets are seen by you Rpi, and strace to see what your program does. My first guess about your connections sometimes not working would be loss of packets. By using wired LAN (Ethernet), you could rule this possibility out.
But the example server code that you're using is a rather bad example. Even if you only want to accept a single client connection at a time, your server should not use blocking waits for any remote message. You should read about using non-blocking I/O, select or poll, and look at examples using these. Also, please read about SO_REUSEADDR, you probably need that one in your server as well.
This line code
char msg[] = " ";
do{
scanf("%s",msg);
will fail miserably if the number of bytes scanned in is larger then 1 character, as msg provides exactly two bytes (from which one is always used as 0-terminator). Feeding more would write out of the bounds of msg and doing so will provoke undefined behaviuor.
To fix this providing at least a minimum of 255 characters to so:
char msg[256] = "";
do{
scanf("%255s",msg);

Passing multiple messages from client -> server and server -> client sockets in C

Could someone help identify why my server cannot accept more than one message from the client?
I am attempting to have the flow be like the following:
1. Client sends size of message to server
2. Server receives the size and sends a response back. In this case 0.
3. Client checks response and then writes message to server.
4. Server reads message and prints it out.
The problem I am getting is that the accept() at step 4 is never unblocking.
CLIENT
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
int main(int argc, char *argv[])
{
int sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in s_address;
s_address.sin_family = AF_INET;
s_address.sin_port = htons(51717);
s_address.sin_addr.s_addr = INADDR_ANY;
if (connect(sock, (struct sockaddr *) &s_address, sizeof(s_address)) < 0) {
printf("ERROR: Cannot connect()\n");
exit(0);
}
char *org_msg = "Hello";
printf("Writing size of Hello\n");
char msg1[1];
msg1[0] = sizeof(org_msg);
write(sock, msg1, sizeof(msg1));
printf("Waiting for response from server\n");
struct sockaddr_in c_address;
socklen_t c_length = sizeof(c_address);
int new_sock = accept(sock, (struct sockaddr *) &c_address, &c_length);
printf("Reading response from server\n");
char stat[1];
read(new_sock, stat, 1);
if (atoi(stat) == 0) {
printf("Writing Hello to server\n");
write(sock, org_msg, sizeof(org_msg));
}
close(sock);
close(new_sock);
}
SERVER
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
int main(int argc, char *argv[])
{
int sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in s_address;
s_address.sin_family = AF_INET;
s_address.sin_port = htons(51717);
s_address.sin_addr.s_addr = INADDR_ANY;
if (bind(sock, (struct sockaddr *) &s_address, sizeof(s_address)) < 0) {
printf("ERROR: Cannot bind()\n");
exit(0);
}
listen(sock, 3);
printf("Waiting for client message\n");
struct sockaddr_in c_address;
socklen_t c_length = sizeof(c_address);
int new_sock = accept(sock, (struct sockaddr *) &c_address, &c_length);
printf("Reading client message\n");
char msg[1];
read(new_sock, msg, 1);
printf("Writing response to client\n");
char stat[1];
stat[0] = '0';
write(new_sock, stat, sizeof(stat));
printf("Waiting for client message\n");
int new_sock2 = accept(sock, (struct sockaddr *) &c_address, &c_length);
printf("Reading client message\n");
char msg2[atoi(msg)];
read(new_sock2, msg2, sizeof(msg2));
printf("MESSAGE: %s\n", msg2);
close(sock);
close(new_sock);
close(new_sock2);
}
You should not call accept() on an already-connected socket. Once you have a connected socket in the server (the socket returned by accept()) you should just keep reading and writing that socket until the connection is closed. The steps for the server should be similar to:
listen_socket = socket(...);
listen(listen_socket, ...);
connected_socket = accept(listen_socket, ...);
read(connected_socket, ...)
write(connected_socket, ...)
read(connected_socket, ...)
write(connected_socket, ...)
...
Similarly the client should just keep reading and writing the socket once it has been connected successfully - the steps for the client should be:
connected_socket = socket(...);
connect(connected_socket, ...);
write(connected_socket, ...);
read(connected_socket, ...);
write(connected_socket, ...);
read(connected_socket, ...);
...
INADDR_ANY works in the server but your client needs to specify what host it's connecting to.
If both are on the same machine, just use 127.0.0.1 or localhost (you'll have to do a transform so that it's the right format)
More information here, but a short answer would be
#define INADDR_LOOPBACK 0x7f000001
and then s_address.sin_addr.s_addr = htonl (INADDR_LOOPBACK)
On the client you try to accept a new connection with the socket you previously connected to the server, which will be bound to a system-chosen port number. The server never tries to connect to the client, so the accept call on the client never returns (actually it may return but with an error, because you never call listen on that socket).
Why not just perform step 3 with the same socket used in the previous steps? If for some reason you do need a new socket, you should create a new socket in the client instead of reusing the previous socket (or call close on the previous socket and then call connect on it again).
BTW if all you need is IPC, sockets are a really bad way to do it. I suggest something like Java RMI.

Resources