Unix Sockets: client stops receiving messages correctly after first message
Info
[root@xilinx Downloads]# uname -a
Linux xilinx 2.6.32-71.el6.x86_64 #1 SMP Wed Sep 1 01:33:01 EDT 2010 x86_64 x86_64 x86_64 GNU/Linux
I'm trying to make a simple chat application using Unix sockets:
After compiling the code, I first start the server on one terminal and it speaks while waiting for a connection. And then I run the client on another terminal on the same computer, it connects successfully. The client then sends the first message. The server receives it fine.
But after that, something strange happens. I have to enter multiple times to get it to work and get the whole message.
Here's a simple conclusion:
Server side
[root@xilinx Downloads]# ./server
Waiting for a connection...
Connected.
Client side
[root@xilinx Downloads]#
[root@xilinx Downloads]#
[root@xilinx Downloads]# ./client
Trying to connect...
Connected.
SingleWord // cleint sends this message to the server
Server side
>received<SingleWord //server receives this- good.
IamServer // Now server sends some message
Client side /// I had to click multiple times to get the whole message
echo> Ia>
echo> mS>
echo> er>
echo> ve>
echo> r
Please help me solve the following:
The code is shown below.
Server.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#define SOCK_PATH "echo_socket"
int main(void) {
int s, s2, t, len;
struct sockaddr_un local, remote;
char str[100];
char str2[100];
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
local.sun_family = AF_UNIX;
strcpy(local.sun_path, SOCK_PATH);
unlink(local.sun_path);
len = strlen(local.sun_path) + sizeof(local.sun_family);
if (bind(s, (struct sockaddr * ) & local, len) == -1) {
perror("bind");
exit(1);
}
if (listen(s, 5) == -1) {
perror("listen");
exit(1);
}
for (;;) {
int done, n;
printf("Waiting for a connection...\n");
t = sizeof(remote);
if ((s2 = accept(s, (struct sockaddr * ) & remote, & t)) == -1) {
perror("accept");
exit(1);
}
printf("Connected.\n");
done = 0;
do {
while (1) {
n = recv(s2, str, 100, 0);
printf(">received<%s", str);
if (n <= 0) {
if (n < 0) perror("recv");
printf("error");
done = 1;
}
//m = fgets(str2,100,stdin);
if (!done)
while (fgets(str2, 100, stdin) > 0) {
if (send(s2, str2, strlen(str2), 0) < 0) {
perror("send");
//if (send(s2, str2, m, 0) < 0) {
//perror("send");
done = 1;
}
}
}
} while (!done);
close(s2);
}
return (0);
}
Client.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#define SOCK_PATH "echo_socket"
int main(void) {
int s, t, len;
struct sockaddr_un remote;
char str[100];
char str2[100];
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
printf("Trying to connect...\n");
remote.sun_family = AF_UNIX;
strcpy(remote.sun_path, SOCK_PATH);
len = strlen(remote.sun_path) + sizeof(remote.sun_family);
if (connect(s, (struct sockaddr * ) & remote, len) == -1) {
perror("connect");
exit(1);
}
printf("Connected.\n");
while (1) {
while (printf("> "), fgets(str, 100, stdin), !feof(stdin)) {
if (send(s, str, strlen(str), 0) < 0) {
perror("send");
exit(1);
}
if ((t = recv(s, str2, strlen(str2), 0)) > 0) {
str2[t] = '\0';
printf("echo> %s", str2);
} else {
if (t < 0) perror("recv");
else printf("Server closed connection\n");
exit(1);
}
}
}
close(s);
return 0;
}
source to share
You have a number of problems in your code:
-
server.c:
-
after
n = recv(s2, str, 100, 0);
, you don't null terminate str before using it - you should have:n = recv(s2, str, 100, 0); str[(n > 0) ? n : 0] = '\0';
-
while(1)
it should bewhile (! done)
if you get an error you get an infinite loop displaying the error - you should have:do { while (! done) {
-
-
client.c:
-
you are using
strlen
inrecv
ont = recv(s, str2, strlen(str2), 0)
- it should be:if ((t = recv(s, str2, sizeof(str2), 0)) > 0) {
-
while (1) { while (printf("> "), fgets(str, 100, stdin), !feof(stdin))
does not do what you expect if eof is on stdin, the outer loop continues - you can write (ifint done = 0
declared above):while (! done) { done = 1; while (printf("> "), fgets(str, 100, stdin) != NULL) { done = 0;
-
And I do not guarantee that there are no other small problems of the same type, and you should multiplex the IO with select
, because at this point, the client and server should talk alternately.
source to share