Read all bytes from socket in c - c

Hello i need to read all data from socket, have such function
void handle_socket(int sockfd) {
int len;
int n;
char buf[1024];
n = recv(sockfd, buf, sizeof(buf) - 1, 0);
while (n > 0) {
buf[n] = '\0';
printf("%s", buf);
n = recv(sockfd, buf, sizeof(buf) - 1, 0);
}
printf("Exiting\n");
}
But i can't see Exiting in terminal, what i am do wrong?
Socket sockfd = socket(AF_INET, SOCK_STREAM, 0);
PS i need to read response from POP3 server i try to find \r\n.\r\n but i can't be sure that this string will be at one buffer(for example \r\n at 1st buffer and .\r\n at 2nd

recv() function doesn't return 0 (EOF) untill process on the other end close connection and there is no data left to read. So you will see "Exiting" when the other process close connection.
Your function override old data by new one. You should decide whether you put a limit on the size of buffer or dynamically expand memory for new data. I don't know what your restrictions are, but I recommend to create FILE instance by calling fdopen() and work with standard functions like fgetc, fgets or getLine.

Related

How do open child sockets get closed?

I have spawned a child process on a while(1) loop that appears to accept ongoing TCP connections. I am looking for confirmation of 'normal' behaviour of a socket child process, assuming the parent process is not dead (I found plenty of advice on how to kill child processes when the parent is dead...).
void
dostuff (int sock, int* count)
{
while(1){
*count = *count +1;
char cnt[20];
sprintf(cnt, "count: %d\n", *count);
int n;
char buffer[bufsize];
bzero(buffer,bufsize);
n = read(sock,buffer,bufsize);
if (n < 0) error("ERROR reading from socket");
fprintf(stderr,"From the client:\n%s",buffer);
char reply[bufsize];
bzero(reply, bufsize);
strcat(reply, cnt);
n = write(sock, reply, bufsize);
if (n < 0) error("ERROR writing to socket");
}
}
I suspect the child process will automatically close when its TCP session is finished, is this correct?
It appears when reconnecting to its current TCP session, the child in effect start at the top of the while loop, incrementing count before reading and writing. Can I rely on this behaviour? Or make it reliable?
So first coding problems: the fprintf(stderr,"From the client:\n%s",buffer);. Even if buffer is inited with zeros you may get bufsize bytes, so the fprintf will read data after end of buffer. And you are in a loop so each read could gives a different size, so you may whatever print "garbage" from previous buffer content.
You should use functions that takes a number of chars to write (i.e. fwrite).
An other point is more a "style" problem: you get n bytes from your read, so why writing back bufsize bytes and not n? The only advantage is to have "constant size" messages.
For the inner loop none of the functions in it are able to leave this loop, or the function, or the program.
You must explicitly leave the loop (using break) or the function (using return) or even the program (with exit), depending on your needs.
In its current state the function reads from the socket. It then prints an error message but continues its job (it is up to you to decide what to do in case of read error). After it prints the message (probably the previous one as you don't clean content) and writes to the socket, which will fail (if the socket is closed, you can't read, you can't write).
So here the main point for you: trying to read/write from/to a closed socket just returns -1 from read/write functions. It's up to you to decide what to do after that.
The function should looks like:
void dostuff (int sock, int* count) {
while(1){
int n;
*count = *count + 1;
char buffer[bufsize];
n = read(sock,buffer,bufsize);
if (n <= 0) {
error("ERROR reading from socket (or EOF)");
close(sock); // close our side whatever
break; // leave the loop (or return)
}
fprintf(stderr,"From the client:\n");
fwrite(buffer, 1, n, stderr); // write the n elements
char reply[bufsize];
reply[0] = '\0'; // no need to clear all buffer
strcat(reply, cnt);
n = write(sock, reply, n); // just write N elements
if (n < 0) {
error("ERROR writing to socket");
close(sock); // close our side whatever
break; // not able to write -> problem
}
}
}

pthreads: wait until read() returns a value > 0

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.

reading from standard in and writing to socket

I would like to read from stdin until I reach end of file and then write that to a socket.
When I do this I don't want to read all of the data and then after reading, write to the socket.
It should be: read a byte of data, write that to the socket, read another byte, write that to the socket, etc. until I reach end of file.
Here is what I have so far:
char *buffer[65535];
while (read(0, buffer, 65535) > 0) {
write(sock, buffer, 65535);
}
sock is the socket file descriptor. I just used 65535 because somewhere I read that it was the max you can read() in.
How does this look?
How does this look?
Answer: a little buggy.
Just because you request 64KiB data doesn't mean you're going to get 64KiB of data. You need to record how much data you did receive, and only write what you read. Hence (noting the change of type for buffer mentioned by WhozCraig in his comment):
char buffer[65536];
int nbytes;
while ((nbytes = read(0, buffer, sizeof(buffer))) > 0)
{
if (write(sock, buffer, nbytes) != nbytes)
{
…process short write…
}
}
There are several ways to process a short write. One is to capture the number of bytes actually written, and keep looping until all the data read has been written. The loop below would replace all of the if (write(…)…) code.
Warning: untested code!
int nleft = nbytes;
int nwritten;
char *start = buffer;
while (nleft > 0 && (nwritten = write(sock, start, nleft)) > 0)
{
nleft -= nwritten;
start += nwritten;
}
if (nwritten < 0)
…process error…
Or you can simply report an error and abandon the writing process, which is much simpler but not as resilient.

CR/LF condition check in C

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
}

recv() functions flag for taking the while buffer in one string [windows C]

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?

Resources