Writing send_all and recv_all functions for sockets in C - c

I am a new C programmer and so you will have to excuse my lack of knowledge. I am trying to use sockets in C on a windows machine to send data back and forth between a client and server. I am using the tools of cygwin with the codeblocks IDE. Simple send and receives were not working and so after some searching I was under the impression my problem was I needed a send_all and recv_all function. I have written the following two functions but receive seems to always get stuck in an infinite loop. I am not really sure why.
void send_all(int socket, void *buffer, int length) {
size_t i = 0;
for (i = 0; i < length; i += send(socket, buffer, length - i, 0)){
printf("Completed: %d bytes \r", i);
}
printf("Send Completed: %d bytes \n", length);
}
void recv_all(int sockfd, void *buffer, int length){
size_t i = 0;
for (i = 0; i < length; i+= recv(sockfd, buffer + i, length - i, 0)){
printf("Completed: %d bytes \r", i);
}
printf("Receive Completed: %d bytes \n", length);
}
I am wondering if it is because the receive doesn't know how many bytes the send is sending it. All advice is appreciated but please keep it constructive. Thanks.

recv() actually returns a signed value (int in Winsock, ssize_t in POSIX). Its return value can be a negative number if a read error occurred, OR if the socket is in non-blocking mode and no data is available. Its return value is zero if the socket was closed gracefully (this would cause an infinite loop in your code).
You will need to check the return value before you add it to your byte counter, to detect both of these conditions.
If your socket is in blocking mode (the default), your code will block indefinitely until the required amount of data has been received, or an error occurs (once you add code to check for that). Given the name of your function this seems to be the behavior you want. If so, your general approach is sound.
ssize_t bytesRead = 0;
while (bytesRead < length)
{
ssize_t rv = recv(/* ... */);
if (rv == 0)
{
printf("Socket closed gracefully before enough data received\n");
break;
}
else if (rv < 0)
{
// if your socket is non-blocking, check for EAGAIN which
// would mean no data is currently available; in this case you
// could do something like call select() on the socket to
// go to sleep until more data comes in
printf("Read error occurred before enough data received\n");
break;
}
bytesRead += rv;
}

Related

What is the best way to determine packet size with recv()?

Extremely new to socket programming and C in general. I am trying to write a basic program to send and receive data between two machines. I understand that recv will not get all your data at once -- you essentially have to loop it until it has read the whole message.
In lieu of just setting a limit on both machines, I have created a simple Message struct on the client side:
struct Message {
size_t length;
char contents[1024 - sizeof(size_t)];
} message;
message.length = sizeof(struct Message);
message.contents = information_i_want_to_send;
When it arrives at the server, I have recv read into a buffer: received = recv(ioSock, &buffer, 1024, 0) (Which coincidentally is the same size as my Message struct -- but assuming it wasn't...).
I then extract Message.length from the buffer like this:
size_t messagelength;
messagelength = *((size_t *) &buffer);
Then I loop recv into the buffer while received < messagelength.
This works, but I can't help feeling it's really ugly and it feels hacky. (Especially if the first recv call reads less than sizeof(size_t) or the machines are different bit architectures, in which case the size_t cast won't work..). Is there a better way to do this?
You have a fixed-size message, so you can use something like this:
#include <errno.h>
#include <limits.h>
// Returns the number of bytes read.
// EOF was reached if the number of bytes read is less than requested.
// On error, returns -1 and sets errno.
ssize_t recv_fixed_amount(int sockfd, char *buf, size_t size) {
if (size > SSIZE_MAX) {
errno = EINVAL;
return -1;
}
ssize_t bytes_read = 0;
while (size > 0) {
ssize_t rv = recv(sockfd, buf, size, 0);
if (rv < 0)
return -1;
if (rv == 0)
return bytes_read;
size -= rv;
bytes_read += rv;
buf += rv;
}
return bytes_read;
}
It would be used something like this:
typedef struct {
uint32_t length;
char contents[1020];
} Message;
Message message;
ssize_t bytes_read = recv_fixed_amount(sockfd, &(message.length), sizeof(message.length));
if (bytes_read == 0) {
printf("EOF reached\n");
exit(EXIT_SUCCESS);
}
if (bytes_read < 0) {
perror("recv");
exit(EXIT_FAILURE);
}
if (bytes_read != sizeof(message.length)) {
fprintf(stderr, "recv: Premature EOF.\n");
exit(EXIT_FAILURE);
}
bytes_read = recv_fixed_amount(sockfd, &(message.content), sizeof(message.content));
if (bytes_read < 0) {
perror("recv");
exit(EXIT_FAILURE);
}
if (bytes_read != msg_size) {
fprintf(stderr, "recv: Premature EOF.\n");
exit(EXIT_FAILURE);
}
Notes:
size_t is not going to be the same everywhere, so I switched to a uint32_t.
I read the fields independently because the padding within the struct can vary between implementations. They would need to be sent that way as well.
The receiver is populating message.length with the information from the stream, but doesn't actually use it.
A malicious or buggy sender could provide a value for message.length that's too large and crash the receiver (or worse) if it doesn't validate it. Same goes for contents. It might not be NUL-terminated if that's expected.
But what if the length wasn't fixed? Then the sender would need to somehow communicate how much the reader needs to read. A common approach is a length prefix.
typedef struct {
uint32_t length;
char contents[];
} Message;
uint32_t contents_size;
ssize_t bytes_read = recv_fixed_amount(sockfd, &contents_size, sizeof(contents_size));
if (bytes_read == 0) {
printf("EOF reached\n");
exit(EXIT_SUCCESS);
}
if (bytes_read < 0) {
perror("recv");
exit(EXIT_FAILURE);
}
if (bytes_read != sizeof(contents_size)) {
fprintf(stderr, "recv: Premature EOF.\n");
exit(EXIT_FAILURE);
}
Message *message = malloc(sizeof(Message)+contents_size);
if (!message) {
perror("malloc");
exit(EXIT_FAILURE);
}
message->length = contents_size;
bytes_read = recv_fixed_amount(sockfd, &(message->contents), contents_size);
if (bytes_read < 0) {
perror("recv");
exit(EXIT_FAILURE);
}
if (bytes_read != contents_size) {
fprintf(stderr, "recv: Premature EOF.\n");
exit(EXIT_FAILURE);
}
Notes:
message->length contains the size of message->contents instead of the size of the structure. This is far more useful.
Another approach is to use a sentinel value. This is a value that tells the reader the message is over. This is what the NUL that terminates C strings is. This is more complicated because you don't know how much to read in advance. Reading byte-by-byte is too expensive, so one normally uses a buffer.
while (1) {
extend_buffer_if_necessary();
recv_into_buffer();
while (buffer_contains_a_sentinel()) {
// This also shifts the remainder of the buffer's contents.
extract_contents_of_buffer_up_to_sentinel();
process_extracted_message();
}
}
The advantage of using a sentinel value is that one doesn't need to know the length of the message in advance (so the sender can start sending it before it's fully created.)
The disadvantage is the same as for C strings: The message can't contain the sentinel value unless some form of escaping mechanism is used. Between this and the complexity of the reader, you can see why a length prefix is usually preferred over a sentinel value. :)
Finally, there's a better solution than sentinel values for large messages that you want to start sending before they are fully created: A sequence of length-prefixed chunks. One keeps reading chunks until a chunk of size 0 is encountered, signaling the end.
HTTP supports both length-prefixed messages (in the form of Content-Length: <length> header) and this approach (in the form of the Transfer-Encoding: chunked header).
There are Two ways to do that...
1.)
Use Binary Synchronous protocol. (Use of STX - Start of Text and ETX - End of Text ) for identification of the Text start and end.
2.)
Attach the number of bytes of data being sent at the start of Data. The socket will read those number of bytes and will get the number of bytes to be received from the socket. Then read all data and get the amount of data required.
Hmm... Seems tough...?? Let me give you an example.
Actual Data need to be sent: ABCDEFGHIJ
New Data format : 0010ABCDEFGHIJ
Data required in server side: ABCDE
recv function will read the first 4 bytes to get the number of bytes of actual data(In loop untill it gets 4 bytes):
int received1= recv(ioSock, recvbuf, 4, 0);
As per the above case, 'recvbuf' will be 0010 converted to an integer will give value as '10' which can be stored in some integer variable. So we have :
int toReadVal = 10
Now all we need is to read these 10 digits in next recv call :
int received= recv(ioSock, recvbuf1, toReadVal, 0);
Finally, we get the value of recvbuf1 as ABCDEFGHIG. Now you can truncate the value as per your requirement.

ntohs() issue : Write Integer in C socket

I am trying to write and read Integer value into/from C socket. Sometimes ntohs() return very big values like 55000 , 32000 etc...Though client is always sending value <1500. If I run the program it happens after 10-15 minutes...Sometimes after 20-30 minutes.
Can you please check below code and tell me
Why this line getting printed ?
printf("Garbage value - ntohs problem ..Exiting... ");
// write exactly n byte
inline int write_n(int fd, char *buf, int n) {
int nwrite, left = n;
int totalwrite = 0;
while (totalwrite != n) {
if ((nwrite = write(fd, buf, left)) <= 0) {
break;
} else {
totalwrite = totalwrite + nwrite;
left -= nwrite;
buf += nwrite;
}
}
if (totalwrite == 0)
return nwrite;
return totalwrite;
}
// send exactly n byte
inline int send_n(int fd, char *buf, int n) {
int nwrite, left = n;
int totalwrite = 0;
while (totalwrite != n) {
if ((nwrite = send(fd, buf, left, MSG_NOSIGNAL)) <= 0) {
break;
} else {
totalwrite = totalwrite + nwrite;
left -= nwrite;
buf += nwrite;
}
}
if (totalwrite == 0)
return nwrite;
return totalwrite;
}
uint16_t nread, len, plength, nsend;
int MTU = 1500;
char buffer[2000];
// Server receive ( Linux 64 bit)
while (1) {
// read packet length
nread = read_n(TCP_SOCKFD, (char *) &plength, sizeof(plength));
if (nread <=0) {
break;
}
len = ntohs(plength);
if (len <=0 || len > 1500 ) {
**printf("Garbage value - ntohs problem ..Exiting... "); // WHY ?**
break;
}
// read packat data
nread = read_n(SOCKFD, buffer, len);
if (nread != len) {
break;
}
}
//---------------------
// CLIENT send ( Android 5 )
while (1) {
nread = read(tunfd, buffer, MTU);
if (nread <= 0 || nread > 1500) { // always <=1500
break;
}
plength = htons(nread);
// send packet lenght
nsend = send_n(TCP_SOCKFD, (char *) &plength, sizeof(plength));
if (nsend != sizeof(plength)) {
break;
}
// send packet data
nsend = send_n(TCP_SOCKFD, buffer, nread);
if (nsend != nread) {
break;
}
}
Thank you
We cannot tell you with certainty what's happening because you cannot provide a verifiable example. Additionally, you've not presented the implementation of read_n(), but supposing that it follows the same model as write_n() and send_n(), we can nevertheless perform some analysis.
Each of the data transfer functions returns a short count in the event that data transfer is interrupted by an error. The client code watches for this, and breaks out of its loop if it detects it. Well and good. The server code does not do this when reading plength, however. Since plength, as a uint16_t, is two bytes in size, a partial read is possible and would go unnoticed by your server code.
In your example, plength is modified only via the one read_n() call presented. Network byte order is big-endian, so the most-significant byte is read first. It is possible that the combination of that byte with the stale one left over from the previous read would represent a number exceeding 1500. For example, if a 221(0x00dd)-byte packet is followed by a 1280(0x0500)-byte packet, and a partial read occurs on the second packet size, then the combined result will be 1501(0x05dd).
I don't presently see any reason to think that the client sends data different in nature than you think it does, and I don't presently see any other way that your server code could give the appearance of receiving different data than the client sends, especially since client and server each abort at the first recognized sign of trouble.
Do note, however, that this code could still be made more robust. In particular, consider that read(), write(), and send() can fail even when there is no problem with the underlying socket or data transfer request. In particular, they can fail with EINTR if the call is interrupted by a signal, and if the socket is in non-blocking mode then they can fail with EAGAIN. There may be others. It does not seem useful to operate your socket in non-blocking mode, but you might indeed want to watch for EINTR and resume reading after receiving it.
I would also suggest that, at least during development, you emit more data about the nature of the error. Call perror(), for example, and afterward print the bad data. You might even consider logging data sent and received.

Send/Read using a TCP socket, anomalies in the byte sizes

I'm trying to implement a working HTTP Client-Server application just to make practice with network programming.
The 2 programs have to follow this basic algorithm:
CLIENT - send a GET request
SERVER - send "+OK\r\n"
SERVER - send file size in bytes
SERVER - send file
CLIENT - send ACK
I'm having a lot of troubles in the reading part, probably because i perform some dirty read on the stream.
These are the 2 reading function that i'm using:
/* Reads a line from stream socket s to buffer ptr
The line is stored in ptr including the final '\n'
At most maxlen chasracters are read*/
int readline (SOCKET s, char *ptr, size_t maxlen)
{
size_t n;
ssize_t nread;
char c;
for (n=1; n<maxlen; n++)
{
nread=recv(s, &c, 1, 0);
if (nread == 1)
{
*ptr++ = c;
if (c == '\n')
break;
}
else if (nread == 0) /* connection closed by party */
{
*ptr = 0;
return (n-1);
}
else /* error */
return (-1);
}
*ptr = 0;
return (n);
}
and:
int readNumber(SOCKET s, long *num, int maxRead)
{
size_t n;
ssize_t nread;
int totRead;
long number=0;
for (n=1; n<maxRead+1; n++)
{
nread=recv(s, &number, sizeof(number), 0);
if (nread == sizeof(number))
{
totRead+=nread;
*num = number;
}
else if (nread == 0) /* connection closed by party */
{
*num = 0;
return (n-1);
}
else /* error */
{
printf("nread = %d\n", nread);
return (-1);
}
}
return (totRead);
}
this is the snippet of the main where i receive the +OK message and then the file size:
memset(rbuf,0,sizeof(rbuf)); //rbuf is the buffer where is store the read
printf("waiting for response...\n");
result = readline(s, rbuf, sizeof(rbuf)); //reading function is above
printf("Byte read(okMsg) = %d\n", result);
if (result <= 0)
//ERROR MANAGEMENT
{
printf("Read error/Connection closed\n");
closesocket(s);
SockCleanup();
exit(1);
}
else
{
long fileLength=0;
unsigned char *fBuf;
//RECEIVE OK
if(!strcmp(rbuf,"+OK\r\n"))
{
puts("+OK\n");
//RECEIVE FILE LEN
int nw = readNumber(s, &fileLength, 1); //reading function is above
printf("Byte read(fDim) = %d\n", nw);
printf("File is %ld bytes long\n", fileLength);
if(nw >0)
{
// RECEIVE FILE
}
}
}
When i send the "+OK\r\n" string the server tells me that it sends 8 bytes, but when i read i find the '\0' char only after 6 bytes.
By the way it reads correctly the message, but when i try to read the file size (that is a long) it gives me back a wrong number.
My opinion is that the stream buffer is dirty, and that i'm reading 2 bytes that are not part of the file size, but i'm not understanding why this happens.
Please ask me more info if i'm not clear enough.
SOLVED:
Thank you all for your answers!!!
You put me in the right mindset to understand what was wrong.
Look like the problem was this declaration in the server:
char *okMsg = "+OK\r\n";
instead of
char okMsg[] = "+OK\r\n";
that lead me to an undefined behavior.
long number=0;
for (n=1; n<maxRead+1; n++)
{
nread=recv(s, &number, sizeof(number), 0);
You forgot to design and implement a protocol to carry the data between your server and your client. Because TCP provides a stream of bytes, your protocol should be defined as a stream of bytes.
How many bytes convey this number? Is "however many bytes a 'long' happens to occupy on my platform" a good answer? What's the semantic meaning of the first byte? Is "whatever the first byte of a 'long' happens to mean on my platform" a good answer?
A good answer would be, "The size shall be conveyed as a 4-byte unsigned integer in little-endian byte order". Then make absolutely sure your code sends and receives in that format.

C - filling TCP socket send buffer

I'm trying to write an experimental client / server program to prove whether the write fails or blocks when the send buffer is full.
Basically, I have an infinite loop on the sender program where I use select() to check if I can write on the buffer (which, I think means that the socket buffer isn't full), if I can write on the buffer than I write() a character. The loop breaks when FD_ISSET(sockfd, &writefds) is false (I can't write on the buffer because it's full).
The reciever program is sleeping for one minute before starting to read(). I expect the sender to fill the buffer within this sleeping time but in fect, the programs never end.
sender:
int main(int argc, char *argv[]) {
char buffer[100];
int sockfd, total = 0, bytes = 0;
fd_set writefds;
sockfd = dial(argv[1], argv[2]);
bzero(buffer, sizeof buffer);
while(1)
{
int ret = 0;
FD_ZERO(&writefds);
FD_SET(sockfd, &writefds);
if((ret = select(sockfd + 1, NULL, &writefds, NULL, 0)) < 0)
{
perror("select");
exit(errno);
}
if(FD_ISSET(sockfd, &writefds))
{
write(sockfd, "a", 1);
total++;
continue;
}
else
{
puts("I can't write in the socket buffer");
break;
}
}
printf("nb chars written: %d\n", total);
return 0;
}
reciever:
int foo(int sockfd) {
char buffer[100];
int t, total = 0;
bzero(buffer, sizeof buffer);
printf("I have a new client\n");
sleep(60);
while((t = read(sockfd, buffer, sizeof buffer)) > 0)
{
total += t;
printf("%d ", total);
}
printf("nb chars read: %d\n", total);
if(t < 0)
{
perror("read");
}
printf("I don't have that client anymore\n");
return 0;
}
Your select timeout is null, so select() will block when the send buffer is full. This means when it returns, the socket is writable, and you'll never get to your code "I can't write in the socket buffer".
See man page http://linux.die.net/man/2/select
If you want a zero timeout, i.e. don't block on select(), you need to pass a pointer to a timeval structure with both fields set to zero.
You're on the right track, but the socket send buffer could be 48k or more. That's a lot of iterations. Try writing 8k at a time, not just one byte. And increase the time before the receiver reads.
NB No real need to test this. It blocks in blocking mode, and fails with EAGAIN/EWOULDBLOCK in non-blocking mode. See the man page.

Send a File with socket in C for Linux

I'm writing a small and simple server (in C language for Linux stations).
A client requests a file to my server, my server asks this file to another server which sends it to my server.
My server should NOT receive ALL the file before sending it to the client BUT must send the bytes of the file so as they arrive.
This is an exercise in school so I can not dissociate myself from this requirement.
I have implemented the function explained below. The problem is that the client receives a non-deterministic number of bytes and NEVER the entire file.
int Recv_and_send_file (int socketa, int socketb, char *buffer, size_t file_size){
size_t n;
ssize_t nread;
ssize_t nwritten;
char c;
for (n=1; n<file_size; n++)
{
nread=recv(socketa, &c, 1, 0);
if (nread == 1)
{
nwritten = send(socketb,&c,1,0);
}
else if (nread == 0)
{
*buffer = 0;
return (-1); /* Errore */
}
else
return (-1); /* Errore */
}
}
*buffer = 0;
return (n);
}
Someone could kindly tell me where I'm wrong?
Is it an stupid idea to change the values ​​SO_SNDBUF and SO_RCVBUF on both the server and the client?
Assuming the file_size is the total number of bytes you want to send, then your for loop will only send file_size - 1 bytes. In other words, you are off by one. Start from 0 instead to fix this:
for (n=0; n<file_size; n++)
{ //..
You capture the return value of send(), but you do not check to see if it was successful or not.
You are treating a 0 return value from recv() the same as an error. Since you do not show what you do after returning -1 from your function, I don't know if this may be contributing to your problem or not.
Certain errors on send() and recv() are "soft", in that you are allowed to retry the operation for those particular errors. One such error is EINTR, but check the documentation on your system to see if there are others.
In order to optimize performance and simplify your code, you can use splice()+pipes. Sendfile enables you to "forward" data between file descriptors, without the copy to user space.
Are you sure you have copied the correct code? That part as it is would not compile, there is a } in the last else which don't match with a corresponding {.
Also, how you get to know the file size? if it's send thru the socket as an integer, bear in mind the possible byte order of the source and destination machines.
Anyway, you are reading one byte at a time, you should improve it this way:
EDIT: use buffer and not the extra buff[2048];
int Recv_and_send_file (int socketa, int socketb, char *buffer, size_t file_size){
ssize_t nread;
ssize_t nwritten;
ssize_t bLeft=file_size;
while (bLeft > 0)
{
nread=recv(socketa, buffer, bleft, 0);
if (nread > 0)
{
nwritten = send(socketb, buffer, nread, 0);
bLeft -= nread;
buffer+=nread;
}
else if (nread == 0)
{
// I think this could raise a memory exception, read below
*buffer = 0;
return (-1); /* Errore */
}
else
{
return (-1); /* Errore */
}
}
// If buffer is allocated with file_size bytes this one will raise a memory exception
// *buffer = 0;
return (file_size-bLeft);
}

Resources