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
}
Related
I am working on a project for school and have run into the following problem. My server is blocking out on recv() despite my client already sending its full message.
This is what I want to happen:
Server Client
recv() <---- send()
send() ----> recv()
This is what is happening:
Server Client
recv() <---- send()
recv() ----- recv()
Some Background
2 Weeks ago I created the client by itself with an already coded server application. When I coded the client it functioned properly with the provided server, so I want to say that the client is wrong, but I don't know how to get the server that I coded to recognize that no more data will be coming in.
Code
Here is the code that I believe is relevant:
Client:
bytesSent = 0;
retVal = send(sock, phrase, msgLen, 0);
bytesSent = retVal;
while (bytesSent < msgLen) {
retVal = send(sock, phrase + bytesSent, msgLen - bytesSent, 0);
if (retVal == SOCKET_ERROR) {
DisplayFatalErr("send() function failed.");
exit(1);
}
bytesSent += retVal;
// May need to re-call send in order to keep sending the data.
}
...
bytesRead = 0;
while (bytesRead < msgLen) {
retVal = recv(sock, rcvBuffer, RCVBUFSIZ - 1, 0);
if (retVal <= 0) {
DisplayFatalErr("recv() function failed.");
exit(1);
}
bytesRead += retVal;
for (int i = 0; i < retVal; i++) {
printf("%c", rcvBuffer[i]);
}
}
Server:
char* rcvBuffer[RCVBUFSIZ]; // RCVBUFSIZ = 50
char* msg = "";
int bytesRead = 0;
do {
if ((bytesRead = recv(clientSock, rcvBuffer, RCVBUFSIZ - 1, 0)) == 0) {
break;
}
if (bytesRead < 0) {
return -1;
}
char* msgConcatenated;
int msgLen = strlen(msg);
msgConcatenated = malloc(msgLen + bytesRead);
if (msgConcatenated != NULL) {
int newMsgLen = strlen(msgConcatenated);
strncpy_s(msgConcatenated, newMsgLen, msg, msgLen);
strncat_s(msgConcatenated, newMsgLen, rcvBuffer, bytesRead);
msg = msgConcatenated;
}
} while (bytesRead != 0);
Let me know if I need to provide extra information.
When using TCP, to signal the other end of the socket that no more data will be sent, a packet with the FIN flag set must be sent. This is accomplished in Winsock by calling the function shutdown with SD_SEND as the second parameter. This will cause the program on the other end of the socket to no longer block when calling recv. Instead, recv will return 0 indicating that the connection has been gracefully closed (unless there is data left that has not been read yet). See the Microsoft documentation on the shutdown function for further information. This documentation page also contains some helpful information about graceful socket closure.
Also, as has been pointed out in the comments, your code contains a memory leak in the following line:
msg = msgConcatenated
In that line, you reassign msg without first freeing the memory that msg is pointing to. Unfortunately, fixing that memory leak is not easy, because you can't simply call free on msg before reassigning it. This is because, in the first iteration of the loop, msg can also be pointing to something else than dynamically allocated memory. Therefore, to fix the leak, you would also have to keep track of what type of memory msg is pointing to, or make it always point to dynamically allocated memory, even when the string is empty (i.e. when it only contains the terminating null character).
I'm working on a client program that will operate as a basic instant messenger. I'm using pthread to to open up a thread dedicated to waiting for a message to be received and the the message to be read. Is using pthread_cond_wait the correct way to go about waiting for read(sockfd, buffer, 256) to be above 0?
void *threadRead() {
while (1) {
bzero(buffer,256);
pthread_cond_wait(&buffer_lock, read(sockfd, buffer, 255) > 0);
n = read(sockfd, buffer, 255);
printf("%s\n",buffer);
}
}
You see I just need to wait until read() comes back with a value above 0 to continue and I can't find the right system to do that. If anyone could link something that would put me on the right track or give me a hint that would be great.
No. pthread_cond_wait() is for waiting on a condition that will be changed by one of your other threads.
If you just want to wait for read() to return something, just call read(). Unless you have specifically marked the socket as non-blocking, it will block the calling thread until there is something to return.
If read() ever returns 0 then it indicates end of file: it means that the socket has been closed on the remote side, so there will never be any more to read.
You should use select() instead, like this
int running;
running = 1;
while (running != 0) /* Just in case you want to end the loop, you can */
{
fd_set rdset;
struct timeval timeout;
timeout.tv_sec = NUMBER_OF_SECONDS_TO_WAIT;
timeout.tv_usec = YOU_CAN_HAVE_MICRO_SECONDS_PRECISION;
FD_ZERO(&rdset);
FD_SET(fd, &rdset);
if (select(fd + 1, &rdset, NULL, NULL, &timeout) == 1)
{
ssize_t length;
char buffer[100];
length = read(fd, buffer, sizeof(buffer));
/* use buffer now */
}
else
{
/* Timed out and still nothing to read */
/* do something meanwhile and retry if */
/* you want to. */
}
running = use_a_function_to_check_this();
}
you can use it in a different thread, but you need to be careful.
Non-blocking IO is difficult, it doesn't matter how you implement it is hard.
One more thing, this
n = read(sockfd, buffer, 255);
printf("%s\n",buffer);
is likely undefined behavior, since apparently buffer is
char buffer[256];
you could
n = read(sockfd, buffer, 255 /* or sizeof(buffer) - 1 */);
buffer[n] = '\0';
printf("%s\n",buffer);
ensuring that buffer is nul terminated.
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 :]
I'm trying to receive a single packet at a time from the server, since packets are going too fast, and each is of undefined size, calling recv() with number of bytes to read will read the first packet and maybe a part of the second packet. Since each packet is NULL terminated, I thought reading byte by byte until a NULL byte is received.
int recvLen = 0;
char TB;
char recvBuffer[1024];
while (recv(Socket, &TB, 1, 0) > 0 && TB != 0 && recvLen < 1024)
{
recvBuffer[recvLen] = TB;
recvLen++;
}
I don't think this method is efficient at all. If the server sent 1024 bytes, recv() will be called 1024 times.
Is there any other method to recv() until a NULL char is received, or some better method than this one I'm using?
EDIT:
i added the packet size infront of the data sent from the server, but now, if a false packet or even sometimes for no reason, packets gets messed up and no correct data is received. here is my code
#define UPLOAD_LEN 2755
int PacketSize, recvLen;
char Size[4];
char recvBuffer[UPLOAD_LEN+1];
while(1)
{
if(recv(Socket,Size,4,0)>0)
{
Size[4] = '\0';
PacketSize = atoi(Size);
if (PacketSize > UPLOAD_LEN || PacketSize <= 0) continue;
recvLen = recv(Socket, recvBuffer, PacketSize, 0);
} else recvLen = -1;
if (recvLen > 0)
{
recvBuffer[recvLen] = '\0';
ProcessData(recvBuffer);
}
else
{
closesocket(Socket);
}
}
I have never understood why communications protocols never support the one use case programmers expect to be able to do: exchange arbitrarily sized blobs with sends and recv's aligned on boundaries.
So theres no real shortcut here. You need to keep a persistent buffer that holds any data left over from the previous call to recv. Keep adding data to the end as you receive it, and return up to the terminating zero each time you find one. You'll probably have at least a partial following packet, so move that to the start of the buffer to serve as your initial state on the next call.
Create a buffer and extract your protocol messages from that. If the buffer does not contain a complete message, then recv() until it does. Here's a simple C implementation to buffer a socket (lightly tested, compiles on MS VS2008):
#include <winsock2.h>
#include <string.h>
typedef struct buffsock {
SOCKET s;
char* buf;
size_t maxlen;
size_t curlen;
} buffsock_t;
void buffsock_init(buffsock_t* bs,SOCKET s,size_t maxlen)
{
bs->s = s;
bs->buf = malloc(maxlen);
bs->maxlen = maxlen;
bs->curlen = 0;
}
void buffsock_free(buffsock_t* bs)
{
free(bs->buf);
bs->buf = NULL;
bs->maxlen = 0;
bs->curlen = 0;
bs->s = INVALID_SOCKET;
}
/* Attempt to fill internal buffer.
* Returns 0 if socket closed.
* Returns number of additional bytes in buffer otherwise.
*/
int buffsock_fill(buffsock_t* bs)
{
int bytes;
bytes = recv(bs->s,bs->buf + bs->curlen,bs->maxlen - bs->curlen,0);
if(bytes == SOCKET_ERROR)
return -1;
bs->curlen += bytes;
return bytes;
}
/* Return up to <bytes> from buffered socket.
* If return value 0 socket was closed.
* If return value >0 and <bytes socket received partial message.
*/
int buffsock_bytes(buffsock_t* bs,size_t bytes,void* msg)
{
while(bs->curlen < bytes)
{
int result;
result = buffsock_fill(bs);
if(result == -1)
return -1; /* error on socket */
if(result == 0)
break;
}
if(bytes > bs->curlen)
bytes = bs->curlen;
memcpy(msg,bs->buf,bytes);
bs->curlen -= bytes;
memmove(bs->buf,bs->buf + bytes,bs->curlen);
return bytes;
}
/* Implmementation of a protocol with two big-endian bytes indicating
* msg size followed by <size> bytes of message.
* Returns -1 if error on socket.
* Returns -2 if partial message recv'd (shouldn't happen as long as
* internal buffer is bigger than max message size).
* Returns -3 if user buffer not big enough to hold message.
* Returns size of message otherwise.
*/
int get_protocol_message(buffsock_t* bs,void* msg,size_t maxlen)
{
int bytes;
u_short len;
bytes = buffsock_bytes(bs,sizeof(u_short),&len);
if(bytes == 0)
return 0; /* socket closed, no more messages */
if(bytes == -1)
return -1; /* error on socket */
if(bytes < sizeof(u_short))
return -2; /* partial message */
len = ntohs(len);
if(len > maxlen)
return -3; /* message exceeds user buffer */
bytes = buffsock_bytes(bs,len,msg);
if(bytes < len)
return -2; /* partial message */
return bytes;
}
Use it like this:
int len;
char msg[256];
buffsock_t bs;
/* open a socket */
buffsock_init(&bs,sock,1024);
len = get_protocol_message(&bs,msg,sizeof(msg));
The key is TCP/IP has no concept of message boundaries, so recv() can return 1 to number of bytes requested. The received buffer could contain multiple or even partial messages.
This code just appends received data into a buffer. The protocol requests bytes from the buffer, and the buffer is filled from the socket. as bytes are removed the remaining buffered data is shifted to the beginning of the buffer.
In this case, two bytes are requested, converted to a length, then the remaining bytes are requested. If a request can't be satisfied, more data is recv'd.
Hope this helps.
There are several ways that you could do this.
Option #1: Before sending out any information, send out an int at the front of your packet which contains the size of the packet. Read this int, and then allocate a buffer which is the length of the int that you just received. Then you can recv() the entire packet at one time.
Option #2: Read in 1024 bytes at a time. recv() will give you back the number of bytes read. You can then use strlen() to figure out if you have more than one packet in your buffer. It would probably make the most sense to make this recursive(assuming that you could have several packets in 1024 bytes); so that you split the packets based on NULL bytes.
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?