Reputation: 157
I've got a simple client/server application. The user writes strings in the console. When he pushes enter string is sent. I can transfer one line correctly, but after it substitutes the first letter of first sent word to each next. For example, if a user sends "Hello", the server will get "Hello", but after, if I send "Hello" again, the server will get "HHello". If I try to clear buffer at the client-side after sending it, it never sends something again.
Server code:
// Server side C/C++ program to demonstrate Socket programming
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#define PORT 57174
int main(int argc, char const *argv[])
{
int server_fd, new_socket, valread;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,
&opt, sizeof(opt)))
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( PORT );
if (bind(server_fd, (struct sockaddr *)&address,
sizeof(address))<0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
if (listen(server_fd, 3) < 0)
{
perror("listen");
exit(EXIT_FAILURE);
}
if ((new_socket = accept(server_fd, (struct sockaddr *)&address,
(socklen_t*)&addrlen))<0)
{
perror("accept");
exit(EXIT_FAILURE);
}
char buffer[1024];
bzero(buffer, sizeof(buffer));
int step = 0;
while(1){
valread = read( new_socket , buffer, 1024);
if(valread == 0)
break;
printf("%s", buffer );
printf("\n");
bzero(buffer, sizeof(buffer));
};
return 0;
}
Client code:
// Client side C/C++ program to demonstrate Socket programming
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#define PORT 57174
int main(int argc, char const *argv[])
{
int sock = 0, valread;
struct sockaddr_in serv_addr;
char *hello = "Hello from client";
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("\n Socket creation error \n");
return -1;
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(atoi(argv[2]));
// Convert IPv4 and IPv6 addresses from text to binary form
if(inet_pton(AF_INET, argv[1], &serv_addr.sin_addr)<=0)
{
printf("\nInvalid address/ Address not supported \n");
return -1;
}
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
printf("\nConnection Failed \n");
return -1;
}
// char buffer[1024] = {0};
unsigned int N = 10, delta=10, i = 0;
char* buf = (char*) malloc (sizeof(char)*N);
while (1) {
buf[i] = getchar();
if(buf[i] == 27)
break;
if(buf[i] == 10){
send(sock , buf , strlen(buf) , 0 );
// bzero(buf, sizeof(buf));
N = 10;
buf = (char*) realloc (buf, sizeof(char)*N);
i = 0;
}
if (++i >= N) {
N += delta;
buf = (char*) realloc (buf, sizeof(char)*N);
}
}
return 0;
}
Upvotes: 0
Views: 1931
Reputation: 32586
if a user sends "Hello", the server will get "Hello", but after, if I send "Hello" again, the server will get "HHello"
This is because you missed an else in your client, in
if(buf[i] == 10){ send(sock , buf , strlen(buf) , 0 ); // bzero(buf, sizeof(buf)); N = 10; buf = (char*) realloc (buf, sizeof(char)*N); i = 0; } if (++i >= N) { N += delta; buf = (char*) realloc (buf, sizeof(char)*N); }
you need to replace
if (++i >= N) {
by
else if (++i >= N) {
else after you sent you buffer and set i to 0 you increment it, and you will memorize the next char at the index 1, the character at the index 0 is still present and you will send it again and again
You also have a problem in your client at
send(sock , buf , strlen(buf) , 0 );
because you do not put a null character in buff needed by strlen to return the expected value, so the behavior is undefined. In fact you do not need strlen, just do
send(sock , buf , i , 0 );
supposing you do not want to send the \n
On your server side
char buffer[1024]; ... valread = read( new_socket , buffer, 1024); if(valread == 0) break; printf("%s", buffer );
you fill each time buffer with null characters but in case you read 1024 characters there is no null character in your buffer and printf will go out of the buffer with an undefined behavior
warning read returns -1 on error, valread == 0 is wrong
remove all your bzero an just do
char buffer[1024];
...
while ((valread = read(new_socket, buffer, sizeof(buffer)-1)) > 0) {
buffer[valread ] = 0;
printf("%s", buffer);
}
notice I used sizeof(buffer) rather than 1024, that allows to be sure to have the right size even you resize buffer
Other remarks for the client :
the variable hello is useless
by definition sizeof(char) values 1, so sizeof(char)*N can be replaced by N everywhere
do not compare the read char with the literal 10 and 27, compare with '\n' and '\e'
you do not manage the EOF in input, for that you need to save the read char in an int rather than a char (like buf[i] is) to compare it with EOF
In the server the variable step is useless
Out of that you use SOCK_STREAM so your socket is a stream (tcp not udp), that means you cannot suppose the size of the data you read each time you call read, I mean if the client sent N bytes that does not mean the server will read N bytes on the corresponding read (if I can say 'corresponding' because there is no correspondence ;-) ).
Supposing the other problems are fixed if you input azeqsd\n you send azeqsd but may be on the server side you will read azeq so print azeq\n and on the next loop you will read sd and print sd\n.
It is also possible the server read a partial or full concatenation of several buffers sent separably by the client.
Do you want that behavior ? if no you need to send the size before each buffer to know how much to read even on several times to constitute the full sent buffer (an other advantage is you no not read byte per
Upvotes: 2