C programming socket buffer - c

Re: this client<->server (foodrequest-foodinfo scenario) I am trying to send receive to a successful client-server connection sock_fd. In this loop, I receive the first information back but the next iteration stops at the keyboard input ie readInFood(). Is there anything wrong with the way I am handling the buffer? or otherwise.
RESPONSE_BUFFER = 2200;
INPUT_BUFFER = 100;
int numbytes;
char foodType[INPUT_BUFFER];
char foodResponse[RESPONSE_BUFFER];
do {
//send a message to server
if (send(sock_fd, readInFood(foodType), INPUT_BUFFER, 0) == -1)
perror("send");
//receive the message
if ((numbytes = read(sock_fd, foodResponse, RESPONSE_BUFFER)) == -1) {
perror("receive");
exit(EXIT_FAILURE);
}
//end the buffer string
foodResponse[numbytes] = '\0';
//print the buffer
printf("\nThis is the information you require: %s", foodResponse);
} while (foodType[0] != 'q' || foodType[0] != 'Q');

My guess is that your socket is blocking because it expects more information or its not getting anything else. In that case perror() will not fire, but your program will continue to wait for info.

Related

Server program not ending when "quit" string entered

I've got a basic linux socket program mostly running that accepts strings from the client to send to the server. When "quit" is typed, my client program ends, but the server one prints out "quit" endlessly until you kill the program. Either I'm not reading the string properly or my logic is off.
Code section...
while (1)
{
//fetch message from client and write to stdout
num_client_bytes = recv(client_sockfd, buf, LEN, 0);
if (-1 == num_client_bytes)
{
perror("server-- recv failed");
}
else
{
printf("client msg: %s", buf);
if (0 == strcmp(buf, "quit\n"))
{
break;
}
}
}
//remove local socket file and close sockets
unlink(SOCKET_NAME);
close(client_sockfd);
close(server_sockfd);
return 0;
You need to memset buf prior to recv
recv will not add '\0' at the end of string read from socket,
also you should check if recv read entire 4 bytes, then change:
strcmp(buf, "quit\n")
to
strncmp(buf, "quit\n",4)// if you are not sure client sends \n

How to use nanomsg survey architecture without while loop?

I was going through nanomsg usage for IPC and wanted to use SURVEY-archetype architecture described here.In this, processes run as client and server and exchange data. Now server has following code (also listed in the provided link):
int server (const char *url)
{
int sock = nn_socket (AF_SP, NN_SURVEYOR);
assert (sock >= 0);
assert (nn_bind (sock, url) >= 0);
sleep(1); // wait for connections
int sz_d = strlen(DATE) + 1; // '\0' too
printf ("SERVER: SENDING DATE SURVEY REQUEST\n");
int bytes = nn_send (sock, DATE, sz_d, 0);
assert (bytes == sz_d);
while (1)
{
char *buf = NULL;
int bytes = nn_recv (sock, &buf, NN_MSG, 0);
if (bytes == ETIMEDOUT) break;
if (bytes >= 0)
{
printf ("SERVER: RECEIVED \"%s\" SURVEY RESPONSE\n", buf);
nn_freemsg (buf);
}
}
return nn_shutdown (sock, 0);
}
Since socket type is NN_SURVEYOR, the while-loop doesn't wait at nn_recv. For client, socket type is NN_RESPONDENT and so, while loop in client waits at nn_recv.
Now since this while loop runs continuously and infinitely, the CPU usage shoots up to 99%. Can you please tell me that is there any other way to make survey architecture using nanomsg.
Try adding yield() call in the end of loop if nothing was received.

UNIX Domain socket programming in C, printing issue

I am having a printing issue with my server. I want there to be simultaneous printing when I have 2 or more clients active on terminals. However, I am only printing from one client at a time. Once I close a client, the other clients are free to write to the server. What can I do to fix my problem?
I have tried to fork the printing section, which I think didn't really do anything. (Just realized if I do this, then the select system call is a waste, i'd rather use the select system call) *edit
while(TRUE) {
FD_ZERO(&readfds);
FD_SET(socket1, &readfds);
FD_SET(socket2, &readfds);
FD_SET(socket3, &readfds);
select(socket3+1, &readfds, NULL, NULL, NULL);
//add socket1
if(FD_ISSET(socket1, &readfds)) {
if((client_socket1 = accept(socket1, NULL, NULL)) < 0) {
perror("accept1");
exit(EXIT_FAILURE);
}
printf("New Connection\n");
puts("Welcome message1 sent successfully\n");
}
//add socket2
if(FD_ISSET(socket2, &readfds)) {
if((client_socket2 = accept(socket2, (struct sockaddr *)&addr2, (socklen_t*)&addr2)) < 0) {
perror("accept2");
exit(EXIT_FAILURE);
}
printf("New Connection\n");
puts("Welcome message2 sent successfully\n");
}
//add socket 3
if(FD_ISSET(socket3, &readfds)) {
if((client_socket3 = accept(socket3, (struct sockaddr *)&addr3, (socklen_t*)&addr3)) < 0) {
perror("accept3");
exit(EXIT_FAILURE);
}
printf("New Connection\n");
puts("Welcome message3 sent successfully\n");
}
//print from socket 3
while( (ready = read(client_socket3, buffer, sizeof(buffer))) > 0) {
printf("%s\n", buffer);
}
//print from socket 2
while( (ready = read(client_socket2, buffer, sizeof(buffer))) > 0) {
printf("%s\n", buffer);
}
//print from socket 1
while( (ready = read(client_socket1, buffer, sizeof(buffer))) > 0) {
printf("%s\n", buffer);
}
}
You need to add your client sockets to the fd_set and select statement before attempting to read from them. Also, you should make all your sockets non-blocking. Otherwise, the read call will block until you get data.
Here's a quick fix that uses recv instead of read to read the sockets, but with the async flag of MSG_DONTWAIT.
I didn't see anywhere where you were closing your client sockets or handling errors properly. So I inserted some code as a hint. Also, it's never a good idea to "printf" a buffer of data from a socket directly. Because you never know if the data you received is null terminated. Always null terminate your buffer after you read the data off the socket.
Change this block of code:
//print from socket 3
while( (ready = read(client_socket3, buffer, sizeof(buffer))) > 0) {
printf("%s\n", buffer);
}
To this:
while (1)
{
int result;
result = recv(client_socket3, buffer, sizeof(buffer)-1, MSG_DONTWAIT);
if ((result == -1) &&
((errno == EAGAIN) || (errno==EWOULDBLOCK)) )
{
// no more data available, but could be available later
// use the socket with "select" above to wait for more data
}
else if ((result == -1) || (result == 0))
{
// remote close or unrecoverable error
close(client_socket3);
client_socket3=-1;
}
else
{
// null terminate the buffer before printing
buffer[result] = '\0';
printf("%s\n", buffer);
}
}

How to use recv to recieve long text strings

I am trying to create a server and client program that sends a string from client to server where the server executes that string and sends the output back to the client. I am doing this in linux and I am very confused why my program isnt working the least bit. Here is the code.
**Client**
int main()
{
//Code to use unix socket here
if (connect(s, (struct sockaddr *)&remote, len) == -1) {
perror("connect");
exit(1);
}
printf("Connected.\n");
while(printf("> "), fgets(str, MAX, stdin), !feof(stdin)) {
if (send(s, str, strlen(str), 0) == -1) {
perror("send");
exit(1);
}
}
done=0;
do {
if(t=recv(s, str, MAX, 0)<0)
perror("recv failed at client side!\n");
str[t] = '\0';
if(strcmp(str, "ENDOFTRANS")==0)
{
printf("\nRead ENDOFTRANS. Breaking loop.\n");
done=1;
}
printf("Server > %s", str);
} while(!done);
}
And then the server code is:
**Server**
#define MAX 1000
int main(void)
{
//Unix socket code
//This process is now a daemon.
daemon();
//Listens for client connections, up to 5 clients can queue up at the same time.
if (listen(s, 5) == -1) {
perror("listen");
exit(1);
}
for(;;) {
int done, n, status;
printf("Waiting for a connection...\n");
t = sizeof(remote);
if ((newsock= accept(s, (struct sockaddr *)&remote, &t)) == -1) {
perror("accept");
exit(1);
}
printf("Connected.\n");
done = 0;
do {
switch(fork())
{
case -1: //ERROR
perror("Could not fork.\n");
break;
case 0: //CHILD
//Accept string from client.
//Edit: Why am I getting an error here? says: Invalid argument.
if(n = recv(newsock, str, MAX, 0)) {
perror("Recv error at server side.\n");
exit(1);
}
str[n]='\0';
if (n <= 0) {
if (n < 0)
perror("recv");
done = 1;
}
printf("String=>%s<",str);
//Redirect socket to STDOUT & STDERR.
test = close(WRITE); assert(test==0);
test = dup(newsock); assert(test==WRITE);
test = close(ERROR); assert(test==0);
test = dup(newsock); assert(test==ERROR);
if (!done)
{
if (str==something)
{
//execute command
}
else {
//Fork and execvp the command
}
//Sends End of Transaction character.
ENDTHETRANS();
exit(0);
}
break;
default: //PARENT
//Parent keeps accepting further clients.
wait(&status);
if ((newsock= accept(s, (struct sockaddr *)&remote, &t)) == -1) {
perror("accept");
exit(1);
}
printf("Connected.\n");
done=1;
break;
}
} while (!done);
}
close(s);
}
Im relatively new to programming in general and from my understanding the client code is good except that when it recieves the text back from the server it only recieves the text in small bits (2 rows at a time). I have to keep pressing enter on client promt to get the rest of the input. I have tried so many things that by this point I dont even know what I am doing wrong anymore.
Firstly, in the server code, after it recieves the string from the client I have a printf("String=>%s<",str); that outputs the string. However when the server prints the output as String=>ls -l the < key at the end gets eaten up somehow. It shouldnt be doing that right?
Any help much appreciated. Please bare in mind that I am a beginner and have only used pipes as inter process communcation before. Now I wanna make my first unix socket program.
Thanks in advance.
The usual problem in cases such as this is not realizing that SOCK_STREAM sockets don't preserve message boundaries. So data sent with a send call might be split up and received in multiple recvs, or it might be coalesced and multiple sends end up in a single recv. Most importantly, when a kernel send buffer fills up, a send call might write partial data (sending only some of the requested data) and return a short return value. You need to test for this and resend the rest of the data.
Another problem that often shows up is issues with line endings (particularly when talking between linux and windows). There may be extra carriage return characters (\r) in the either the client or server that confuse the other side. These tend to result in apparently missing or truncated output when printed.
edit
The line
if(t=recv(s, str, MAX, 0)<0)
is equivalent to
if(t = (recv(s, str, MAX, 0)<0))
that is, it sets t to 0 or 1 depending on whether there was an error or not. As with most errors of this type, turning on warnings will give you some indication about it.

C: printf non printing \n

In C, I ask the server to print the content of any messages that it receives. All messages follow the format: "Message: /counter/".
while (1){
length = sizeof(struct sockaddr);
/* receive from client */
lenstr = recv(newfd, buff, 20000, 0);
if (lenstr == -1){
perror("recv(): ");
exit(1);
}
buff[lenstr] = '\0';
printf("Received: %s \n", buff);
/* send back to client*/
if (send(newfd, buff, lenstr, 0) < 0){
perror("send(): ");
exit(-1);
}
When I run the server, messages appear one after the other, without going to the new line. What am I missing here? (connection is TCP here)
Thanks.
The data it receives from the socket may contain zeroes or control characters. These should not be printed.
Try using the following function to dump received data into stdout. It replaces all non-printable characters with a dot:
void dump_buf(char const* buf, size_t buf_len) {
char const* buf_end = buf + buf_len;
while(buf != buf_end) {
char c = *buf++;
putchar(isprint(c) ? c : '.');
}
putchar('\n');
}
// ...
lenstr = recv(newfd, buff, 20000, 0);
if (lenstr == -1) {
perror("recv(): ");
exit(1);
}
dump_buf(buff, lenstr);
TCP doesn't have "messages", it handles continuous byte streams in both directions. You are just reading whatever is less between the received data up to that instant and your 2000. Perhaps you really want Stream Control Transmission Protocol? Or mark message ends in some way (perhaps by '\n'), and read character by character? Or just read the length of a single message (if they are fixed length, that is)?

Resources