Im learning about Winsock and Im having a strange issue when sending and receiving a simple string. Here's my code (pure C):
Client:
//...
//Declarations and stuff
//----------- SEND SOME DATA -------------------------------------------------
char string1[] = "string-1";
int bytes_sent = 0;
bytes_sent = send(client_socket, string1, strlen(string1), 0);
printf("BYTES SENT: %i\n", bytes_sent);
printf("\n-----------------------------------------------\n\n");
system("pause");
//...
Server:
//...
//Declarations and stuff
//----------- START LISTENING FOR REQUESTS ------------------------------------
SOCKET ClientSocket;
#define BUFFER_SIZE 256
int size;
struct sockaddr_in client_info;
char client_ip[16];
char data_received[BUFFER_SIZE];
int bytes_received = 0;
listen(ListenSocket, SOMAXCONN);
while(1){
ClientSocket = accept(ListenSocket, (struct sockaddr *)&client_info, &size);
strcpy(client_ip, inet_ntoa(client_info.sin_addr));
do{
bytes_received = recv(ClientSocket, data_received, BUFFER_SIZE, 0);
if(bytes_received > 0){
printf("DATA RECEIVED FROM %s: %s (%i bytes)\n", client_ip, data_received, bytes_received);
}
}while(bytes_received > 0);
printf("\n-----------------------------------------------\n\n");
}
//...
The problem is that the server prints my string + some strange symbols (see the pic).
Strange symbols
Im using a stream socket. The example is very simple so I dont know what could be wrong. The problem disappears (server prints OK the string) if I randomly modify the string, or the server's buffer size, or both. The problem fixes if in the send() call i use sizeof() instead of strlen(). Im a little bit lost here. Please be kind if i have missed something, this is my very first post here. I can provide the whole code (its basically the winsock start and the socket definition) .
The data you send does not contain a terminating null character:
bytes_sent = send(client_socket, string1, strlen(string1), 0);
...because strlen does not count the terminating null. This isn't exactly the problem in itself, but rather is coupled with the fact that on the receiving side:
char data_received[BUFFER_SIZE];
// ...
bytes_received = recv(ClientSocket, data_received, BUFFER_SIZE, 0);
data_received is not initialized, and you can receive up to BUFFER_SIZE bytes. This means that since the data you send is not null-terminated:
If bytes_received < BUFFER_SIZE, the rest of data_received may not be initialized so accessing/printing would be undefined behavior. It's actually not 100% clear, as the documentation says:
[...] calling recv will return as much data as is currently available—up to the size of the buffer specified [...]
...so it may mean that the rest of the buffer is left untouched.
If bytes_received == BUFFER_SIZE, there is no null-terminator, so printf will invoke undefined behavior by trying to print it, since it doesn't know where the string stops and will overrun the array.
The easiest ways to fix these are either to send a null terminator:
bytes_sent = send(client_socket, string1, strlen(string1)+1, 0); // +1 here
bytes_sent = send(client_socket, string1, sizeof(string1), 0); // same as above
...or receive a byte less and put the null terminator on the receiving size:
bytes_received = recv(ClientSocket, data_received, BUFFER_SIZE-1, 0); // -1 here
data_received[bytes_received] = 0;
I'd personally go with the first.
So the problem is that you're not sending the terminating NUL byte, but you seem to be treating the received string as a C string (i. e. you assume it's NUL-terminated). To fix it, instead of
bytes_sent = send(client_socket, string1, strlen(string1), 0);
write
bytes_sent = send(client_socket, string1, strlen(string1) + 1, 0);
Also, you mentioned that "nobody uses strlen(s) + 1" - perhaps because they pay attention to the number of bytes received at the receiving side.
Try set the length of all your string data and then terminate the string in server like that:
bzero(data_received, sizeof(data_received));
bytes_received = recv(ClientSocket, data_received, BUFFER_SIZE, 0);
data_received[bytes_received] = '\0';
If this not resolve, perhaps the #H2CO3 can help you reading better what you ask :]
Related
I'm writing some server/client program in C Windows. I don't know if I'm sending and receiving buffers the right way, on google I only see people error checking it but not checking if the send() function sent less bytes then expected. This is an example from my project:
Client:
// send buffer size
uint32_t num = htonl(sizeBuffer);
char* converted_num = (char*)#
res = send(ClientSocket, converted_num, sizeof(uint32_t), 0);
if (res == SOCKET_ERROR)
{
printf("error send\n");
}
// send buffer
while (totalSent < sizeBuffer)
{
sent = send(ClientSocket, totalBuffer, sizeBuffer, 0);
totalSent += sent;
printf("sent: %d\n", sent);
printf("totalSent: %d\n", totalSent);
}
Server:
// recv buffer size
char b[sizeof(uint32_t)];
r = recv(s, b, sizeof(uint32_t), 0);
if (r == SOCKET_ERROR)
{
printf("error recv\n");
}
uint32_t sizeBuffer = ntohl_ch(&b[0]);
// recv buffer
while (totalReceived < sizeBuffer)
{
received = recv(s, buffer, sizeBuffer, 0);
strcat(totalBuffer, buffer);
bzero(buffer, 18384);
totalReceived += received;
printf("received: %d\n", received);
printf("totalReceived: %d\n", totalReceived);
}
printf("%s", totalBuffer);
The reason I use strcat() is because when I use printf() inside the while() loop it gets printed weirdly, like the previous buffer gets printed and the new buffer gets printed on top. I don't know why it behaves like this.
Is this the right way to send and receive buffers? And do I also have to check whether the size (num) of the buffer is send correctly, like how I send the buffer itself? If yes, how can I do that?
I'm doing a little project of TCP connection by C language, and the problem with my code is mentioned in the title. And the following is the uploading part of my code
Client Side:
FILE * fp = fopen(f2d, "rb+");
if(fp == NULL) perror("Fail to upload(client)");
else
{
fseek(fp, 0, SEEK_END);
int filesize = ftell(fp);
memset(buf, '\0', MAX_SIZE);
sprintf(buf, "%d", filesize);
send(serverSocket, buf, strlen(buf), 0); //send the filesize to the server
rewind(fp);
int byteNum = 0, z = 0;
printf("Uploading......\n");
while((z += byteNum) < filesize)
{
memset(buf, '\0', MAX_SIZE);
byteNum = fread(&buf, sizeof(char), sizeof(buf), fp);
printf("Bytes read to buf : %d\n", byteNum);
send(serverSocket, buf, sizeof(buf), 0);
printf("Totally sent bytes: %d\n", z);
}
printf("Upload completed.\n");
}
fclose(fp);
Server Side:
printf("Upload Requested.\n");
f2df = fopen(buf + 4, "wb+");
if(f2df == NULL) perror("Fail to upload(server)");
else
{
memset(buf, 0, MAX_SIZE);
recv(clientSocket, buf, sizeof(buf), 0); //receive the filesize
int filesize = atoi(buf);
int recvNum = 0, recv_Num = 0;
while((recvNum += recv_Num) < filesize)
{
memset(buf, 0, MAX_SIZE);
recv_Num = recv(clientSocket, buf, sizeof(buf), 0);
fwrite(&buf, sizeof(char), sizeof(buf), f2df);
printf("Bytes received from recv: %d\n", recv_Num);
printf("Totally received bytes: %d\n", recvNum);
}
printf("Upload completed.\n");
}
fclose(f2df);
The idea of my code is to send and receive the bytes until it reaches the filesize. But with a very high frequency(well, sometimes it functions normally, all bytes are transferred to the server) that the server seems to miss some bytes sent from the client(and the return value of "recv" function will then be zero after the client has sent all the bytes to the server, which makes the terminating condition of the while loop never be reached), which then causes an infinitive loop on the server side.
P.S. all the other functions are without problems(e.g. sending and receiving filesize, the actual number of the filesize... etc), I had tested them all. And there's also no problem on the client side.
And the following is the screenshot of the problem
So can anyone help me out with that, I've been trying to deal with this for weeks, thanks a lot in advance!
Go through you entire client and server code and fix:
1) All those times where you do not handle correctly the results returned from system calls. This especially applies to the result returned by recv() which can be negative, (error), zero, (peer closed the connection), or some positive number less than, or equal to, the number of bytes requested - the ONLY WAY YOU CAN TELL FOR SURE HOW MANY BYTES HAVE BEEN READ IN TO THE BUFFER. Forget the number of bytes requested in the call and any memset/bzero before, and/or strlen/whatever after, it returns, they are all inadequate/misleading.
2) All those times where you assume that, just because you request the recv() of X bytes and recv() returns a positive number, that number will be X.
3) All those times that you call any str* C-style library calls on any buffers that are not 100% guaranteed to be NULL-terminated.
The main problem is the (not) handling of the send() return value, because even in the absence of any error condition, send() may return a smaller value than requested (e. g. if a buffer is full). After each loop cycle in the client, you increment z by the number of bytes read to buf, but disregard that a smaller number of bytes may have been sent. This leads to the outcome that the client loop completes without having sent all data, despite of incorrectly saying so. Change that e. g. to:
printf("Uploading......\n");
while (z < filesize)
{
byteNum = fread(buf, sizeof(char), sizeof buf, fp);
printf("Bytes read to buf : %d\n", byteNum);
int sent = 0;
while (byteNum > 0)
{
int ret = send(serverSocket, buf+sent, byteNum, 0);
if (ret < 0) { perror("send"); goto fail; }
sent += ret, byteNum -= ret;
printf("Totally sent bytes: %d\n", z += ret);
}
}
printf("Upload completed.\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)?
I am testing my TCP echo server, with Telnet, I can see that the client connects to the server and sends a charcter and in return the server returns a string to the client.
Now my problem is by using this recv() in a infinite loop I can only receive one character (even though the client tends to send a string).
This is how I am doing to receive the datagram from the client
TCP SERVER
while(1)
{
socket = accept(server_socket, (struct sockaddr *)&client_address, (socklen_t)&client_length);
recv(socket, recv_buffer, sizeof(recv_buffer), 0);
printf("Received string from client is %s", recv_buffer);
/*then I send my string to the client*/
send(socket, send_buffer, sizeof(send_buffer), 0);
}
Here is my problem that my recv() routine reads only one character even though the client wants to send a whole string. Is there a way how I can make this recv() routine wait before it receives all the characters from the client and then send a response to the client.
Any suggestions would be appreciated
Regards
Well, you are doing something wrong. Look at the definition of recv:
int recv(int s, void *buf, size_t len, int flags);
So it recieves len amount of bytes. You passed sizeof(recv_buffer) as the len parameter. Now I'm guessing recv_buffer is defined as a char*. Getting the sizeof of a pointer means that you get the amount of bytes necessary to store that pointer, instead of the memory it points to.
Do something like this instead:
const int buf_len = 100;
char recv_buffer[buf_len];
recv(socket, recv_buffer, buf_len, 0);
printf("Received string from client is %s", recv_buffer);
You need to build up the string you are receiving yourself in a loop, using the return value of recv() to find how many bytes you actually got. TCP/IP does not guarantee that all the data sent with one call to send() can be received with one call to recv(). And you must examine the return value of every sockets function you call to check for actual lengths sent/received, and for errors.
Your code is a disaster (sorry for being blunt, but it is best to be straight).
recv() returns the number of bytes actually read. Not only that but it will not clear the previous contents of the buffer and it will fill up right to the the end of the buffer if there is data available. All this means that you cannot treat the content of the buffer as a null terminated string.
You need to do something like:
ssize_t bytesRead = 1;
char recv_buffer[SOME_SIZE];
while (bytesRead > 0)
{
int bytesRead = recv(socket, recv_buffer, SOME_SIZE, 0);
if (bytesRead > 0)
{
// do something with the bytes. Note you cannot guarantee that the buffer contains a valid C string.
}
}
if (bytesRead == -1)
{
// report error from errno
}
else
{
// bytesRead == 0 have reached end of file (i.e. socket closed at other end)
}
There is no way to get recv to wait until the buffer is full before returning. It will wait until there are some bytes available and then return. The same applies to send by the way. You can't assume with one call to send that all of your bytes have actually been sent. You need to put send in a loop too:
ssize_t totalBytesWritten = 0;
ssize_t bytesWritten = 0;
while (bytesWritten >= 0 && totalBytesWritten < bytesToWrite)
{
bytesWritten = send(socket, sendBuffer + totalBytesWritten, bytesToWrite - totalBytesWritten, 0);
if (bytesWritten > 0)
{
totalBytesWritten += bytesWritten;
}
}
if (bytesWritten == -1)
{
// error
}
This code sends and recv s txt file perfectly but cannot do it to otehr formats like .exe or .img. Please help me with these as I need to use htonl or htons??
Take a look!!
Here is the server side recv function ::
if (socket_type != SOCK_DGRAM)
{
fi = fopen (final,"wb");
retval = recv(msgsock, recv_buf, strlen(recv_buf), 0);
/*recv_buf[retval] = '\0';
fprintf (fi,"%s",recv_buf);*/
int i;
i=atoi(recv_buf);
char *q;
q=(char *)malloc(i*sizeof(char));
retval = recv(msgsock, q, strlen(q), 0);
//printf ("%s",q);
fwrite(q,i,1,fi);
fclose(fi);
}
else
{
retval = recvfrom(msgsock,recv_buf, sizeof(recv_buf), 0, (struct sockaddr *)&from, &fromlen);
printf("Server: Received datagram from %s\n", inet_ntoa(from.sin_addr));
printf ("SOCK_DGRAM");
}
if (retval == SOCKET_ERROR)
{
fprintf(stderr,"Server: recv() failed: error %d\n", WSAGetLastError());
closesocket(msgsock);
//continue;
}
else
printf("Server: recv() is OK.\n");
if (retval == 0)
{
printf("Server: Client closed connection.\n");
closesocket(msgsock);
//continue;
}
printf("Server: Received %d bytes, data from client\n", retval);
The client side sending function :::
void send_command()
{
int bytesent;
FILE *file_out;
//file_out = fopen(file_path,"rb");
char str_all[100000];//flag [30]="end";
///////////////////////getsize//////////////
char fsize[5];
int filesize;
file_out = fopen(file_path, "rb");
fseek(file_out, 0, SEEK_END);
filesize = ftell(file_out);
rewind (file_out);
itoa (filesize,fsize,10);
/////////////////////////////////////////////
send (ConnectSocket, fsize, strlen (fsize), 0);
char *r = (char *)malloc (filesize * sizeof(char));
fread(r,filesize,1,file_out);
bytesent = send( ConnectSocket, r, strlen(r), 0 );
printf("\nClient: Bytes sent: %ld\n", bytesent);
fclose (file_out);
/*while (fscanf(file_out,"%s",&str_all) != EOF)
{
bytesent = send( ConnectSocket, str_all, strlen(str_all), 0 );
printf("\nClient: Bytes sent: %ld\n", bytesent);
//Sleep(500);
}*/
/*printf("%s",flag);
send( ConnectSocket, flag, strlen(flag), 0 );*/
WSACleanup();
//return 0;
}
OK, there are multiple issues with your program.
You are transferring binary data. The receiver is only going to see a sequence of bytes. There is no way for the receiver to know the end of the data, since all possible values of char are legal data values. If you were sending text data, you could say that a 0 signifies the end of the data, but now you can't. So, you have to decide on a "protocol" between the server and the client—the simplest is that the server sends the length of the data in the first 4 bytes (read up on ntonl() and ntohl() for how to do this portably). Then, the receiver will know exactly how many bytes to read.
You declare the receiver buffer as char *recv_buf, and similarly for recv_buf1. You don't allocate any storage for any of the two pointers, so they aren't pointing to anywhere useful. Then, your recv call is: recv(msgsock, recv_buf, sizeof(recv_buf), 0); This also has problems. The first is the one mentioned above: you don't have storage for recv_buf. The second is that after you do allocate storage for recv_buf, you are taking the size of a char pointer instead of the length of the buffer recv points to. One easy way to solve both the issues would be to declare recv_buf as: char recv_buf[SIZE]; and then use sizeof recv_buf in the recv() call.
I haven't looked at the rest of your code. You probably need a good C and network programming introduction.
I think you're confusing the null-termination of a C string with the end of a packet sent on a socket. There is no "termination" of a packet, it's just a string of bytes. Zeros are completely legal, and you pass (and receive) the length explicitly. You certainly don't need to use the out-of-band facilities to receive multiple packets. Can you be more specific about what you're asking?