I am writing a simple server/client socket in C. The client asks the user to input a message and the server responds by repeating the same. The problem is when I send a message from the client the server responds back by appending extra character. How do I fix this.
This is my Client code
while(1) {
bzero(buffer, BUFSIZE);
printf("Enter Message: ");
scanf("%s", buffer);
//send some data
if(send(socket_fd, buffer, strlen(buffer), 0) <0) {
fprintf(stderr,"sending failed\n");
return 1;
}
//receive a reply from the server
if(recv(socket_fd, server_reply, BUFSIZE,0)<0)
{
fprintf(stderr,"failed to reply. \n");
break;
}
fprintf(stdout, "Reply: %s\n ", servreply);
}
This is my server code
int read_size;
while((read_size = recv(client_socket_fd, buffer, BUFSIZE,0))>0)
{
// Reply back to the client
if (0 > write(client_socket_fd, buffer, strlen(buffer))) {
fprintf(stderr, "could not write back to socket\n");
} else {
fprintf(stdout, "message back to client\n");
}
}
if(read_size==0)
{
fprintf(stderr,"disconnected.\n");
fflush(stdout);
}
else if(read_size==-1){
fprintf(stderr, "error.\n");
}
This is the output
Enter Message: welcome
Reply: welcome
Enter Message: hello
Reply: hellome
Enter Message: hi
Reply: hillome
You need a string in order to use strlen(). Your arrays are not strings, rely on read_size instead for the length of the buffer.
Strings in c are just a sequence of printable characters followed by a '\0', and none of your arrays has any '\0' so strlen() is causing undefined behavior. The strlen() function actually scans the string until it finds the '\0' and in the process it counts how many characters were there.
#Iharob's answer is correct. Basically, change the line:
write(client_socket_fd, buffer, strlen(buffer))
to:
write(client_socket_fd, buffer, read_size)
It isn't. You are printing junk at the end of your buffer. You're also ignoring end of stream.
if(recv(socket_fd, server_reply, BUFSIZE,0)<0) {
fprintf(stderr,"failed to reply. \n");
break;
}
fprintf(stdout, "Reply: %s\n ", servreply);
should be
int count;
if((count = recv(socket_fd, server_reply, BUFSIZE,0))<0) {
fprintf(stderr,"failed to reply. \n");
break;
}
else if (count == 0) {
// EOS
fprintf(stderr, "peer has disconnected.\n");
break;
} else {
fprintf(stdout, "Reply: %.*s\n ", count, servreply);
}
Your 'write back to the client' is also incorrect:
if (0 > write(client_socket_fd, buffer, strlen(buffer))) {
should be
if (0 > write(client_socket_fd, buffer, read_size)) {
Related
I want to find a way to exit from the "loop in question" (see below) with keeping the program running, I mean : In the program there must be the message: "preparing to send informations, exit to stop !" if the user doesn't type exit, the program must still running without waiting the user to click in a character and then enter. The informations must be sent continuously until the user type exit to quit the program.
I hope I explain well the problem, and I'm sure that there is an easy solution
Thank you in advance for your help
do
{
/* menu */
printf("\r\n");
printf("1 : Start, Sending Informations.\r\n");
printf("2 : Quit.\r\n");
printf("choice : ");
scanf("%d", &nChoice);
printf("\n Trying to do a connection \n \r");
/* if connection is not established, call accept, TCP SERVER */
if (fd_client == -1)
{
printf("ready to accept...\n");
fd_client = accept(fd_listen, (struct sockaddr*)&client_addr, &addrlen);
if (fd_client >= 0)
{
printf("accept: %s, port %d\r\n", inet_ntoa(client_addr.sin_addr), htons(client_addr.sin_port));
}
}
if (fd_client < 0)
{
printf(" connection is not established, continue to accept\n");
/*connection is not established, continue to accept*/
continue;
}
FD_ZERO(&rfd);
FD_ZERO(&wfd);
FD_ZERO(&efd);
FD_SET(fd_tty, &rfd);
FD_SET(fd_client, &rfd);
maxfd = (fd_tty > fd_client ? fd_tty : fd_client) + 1;
/*connection is established, call select to see if any data arrived from the GPS*/
printf("connection is established, seeing if any data arrived\n");
char chaine1[256];
char chaine2[] = "exit";
int i;
if (nChoice == 1)
{
do // THE LOOP IN QUESTION
{
printf("preparing to send informations, exit to stop !\n");
i = strcmp(chaine1, chaine2); // Building the condition to exit
scanf("%s", chaine1);
fflush(stdin);
// printf ("i= %d\n",i);
ret = select(maxfd, &rfd, &wfd, &efd, &tm);
if (ret < 0) // Select failed
{
printf("select fail\r\n");
break;
}
else if (ret == 0)
{
continue; /*no data arrived, continue to call select*/
}
else
printf("data is arriving \n");
if (FD_ISSET(fd_tty, &rfd)) /*tty port has data to be read*/
{
ret = read(fd_tty, buf, sizeof(buf));
if (ret <= 0)
{
printf("read tty port fail\r\n");
break;
}
if (send(fd_client, buf, ret, 0) < 0) /*send data to ethernet*/
{
printf("send to ethernet fail\r\n");
break;
}
}
if (FD_ISSET(fd_client, &rfd)) /*tcp client has data to be read*/
{
ret = recv(fd_client, buf, sizeof(buf), 0);
if (ret < 0)
{
printf("read from ethernet fail\r\n");
break;
}
else if (ret == 0)
{
printf("disconnect by remote\r\n");
close(fd_client);
fd_client = -1;
continue; /*continue to accept...*/
}
if (write(fd_tty, buf, ret) < 0) /*send data to tty port*/
{
printf("write to tty fail\r\n");
break;
}
}
} while (i != 0 ); // The exit condition
}
} while(nChoice != 2);
Simple thing you can do is to wait for a timeout. But with scanf you can't do that so you can go for a select() call for the event at stdin and proceed if no event within that time.
Please check the following link
http://cboard.cprogramming.com/c-programming/96544-unblock-scanf-call.html
Hope this helps.
i think it should be noted that fflush(); is designed for output streams and is undefined when used on input streams, 1 way to get around the problem would be scanf(" %s", chaine1); or create a function to clear input buffer.
I'm making this simple example from server to client where the server functions as a echo server! So the client gets input from the user and sends it to the server, the server then sends it back.
I just got stuck on the input from the user. I used stuff like getchar, scanf and fgets. But when I start typing and press ENTER, then it should continue to the next thing in the program... Sadly that ain't happening.
Here is my code for the message part:
while(1)
{
char message[1000], servermessage[1000];
printf("You: ");
scanf("%s", message);
printf("%s\n", message);
if (send(sock, message, strlen(message), 0) < 0)
{
printf("sending failed\n");
return (EXIT_FAILURE);
}
int received = recv(sock, servermessage, sizeof(servermessage), 0);
if (received < 0)
{
printf("received failed\n");
return (EXIT_FAILURE);
}
servermessage[received] = '\0';
printf("Server: %s\n", servermessage);
}
close(sock);
After you type the first time, you call recv(), it will block until there is some data to read, you client didn't read any data, so nothing happen. You need check your echo server to find what's wrong. If you need a echo server to test your client, you can use the code for server here.
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.
I have a function that reads a file from a server and returns the data:
int readMessageFromServer(int fileDescriptor) {
char buffer[MAXMSG];
int nOfBytes;
nOfBytes = read(fileDescriptor, buffer, MAXMSG);
if(nOfBytes < 0) {
perror("Could not read data from server\n");
exit(EXIT_FAILURE);
}
else
if(nOfBytes == 0)
return(-1);
else
printf("Server Message: %s\n", buffer);
return(0);
}
The problem is with the line
printf("Server Message: %s\n", buffer);
If I change this line to
printf("Server Message: %s\n>", buffer);
It refuses to print the '>' sign until it gets more data.
Is this a known limitation or am I doing something wrong?
I should probably add that the call to this function looks like this:
while(readMessageFromServer(sock) > 0) {continue;};
Besides the fact that you probably wanted to write the > inside the quotes, you'll need to flush the output buffer by calling fflush(stdout). The buffers are usually only flushed after newlines.
nOfBytes = read(fileDescriptor, buffer, MAXMSG);
There is no guarantee how many bytes you read or whether they constitute a null terminated string. At a minimum you should change to something like this:
int readMessageFromServer(int fileDescriptor) {
char buffer[MAXMSG];
int nOfBytes;
nOfBytes = read(fileDescriptor, buffer, MAXMSG - 1);
if(nOfBytes < 0) {
perror("Could not read data from server\n");
exit(EXIT_FAILURE);
}
else
if(nOfBytes == 0)
return(-1);
else
{
buffer[nOfBytes] = '\0';
printf("Server Message: %s\n", buffer);
return(0);
}
printf uses stdout which is a buffered output.
Changing printf with fprintf(stderr, ...) should solve your problem.
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)?