Hey all, I have this strange problem with recv(). I'm programming client/server where client send() a message (a structure to be exact) and server recv() it. I am also working with multiple sockets and select().
while(1)
{
readset = info->read_set;
info->copy_set = info->read_set;
timeout.tv_sec = 1;
timeout.tv_usec = 0; // 0.5 seconds
ready = select(info->max_fd+1, &readset, NULL, NULL, &timeout);
if (ready == -1)
{
printf("S: ERROR: select(): %s\nEXITING...", strerror(errno));
exit(1);
}
else if (ready == 0)
{
continue;
}
else
{
printf("S: oh finally you have contacted me!\n");
for(i = 0; i < (info->max_fd+1); i++)
{
if(FD_ISSET(i, &readset)) //this is where problem begins
{
printf("S: %i is set\n", i);
printf("S: we talking about socket %i son\n", i); // i = 4
num_bytes = recv(i, &msg, MAX_MSG_BYTE, 0);
printf("S: number of bytes recieved in socket %i is %i\n", i, num_bytes); // prints out i = 0 what??
if (num_bytes == 0)
{
printf("S: socket has been closed\n");
break;
}
else if (num_bytes == -1)
{
printf("S: ERROR recv: %d %s \n", i, strerror(errno));
continue;
}
else
{
handle_request(arg, &msg);
printf("S: msg says %s\n", msg->_payload);
}
} // if (FD_ISSET(i, &readset)
else
printf("S: %i is not set\n", i);
} // for (i = 0; i < maxfd+1; i++) to check sockets for msg
} // if (ready == -1)
info->read_set = info->copy_set;
printf("S: copied\n");
}
the problem I have is that in read_set, 0~3 aren't set and 4 is. That is fine. But when i call recv(), i suddently becomes 0. Why is that? It doesn't make sense to me why recv() would take an socket file descriptor number and modify to another number. Is that normal? Am I missing something?
S: 0 is not set
S: 1 is not set
S: 2 is not set
S: 3 is not set
S: 4 is set
S: we talking about socket 4 son
S: i is strangely or unstrangely 0
S: number of bytes recieved in socket 0 is 40
That's what it prints out.
recv cannot modify its first argument, since it is taken by value.
You don't show where you've declared msg or i, but based on this line
printf("S: msg says %s\n", msg->_payload);
Where you use the -> operator on msg, I assume it's probably like this:
struct somestruct* msg = malloc(sizeof(struct somestruct));
int i;
Then you do this:
num_bytes = recv(i, &msg, MAX_MSG_BYTE, 0);
Note that msg is already a pointer, so &msg is a pointer to the pointer.
What this will then do is receive data and try to store it in the place where the msg pointer itself is, not the place that msg points to. Typically, pointers are only 4 bytes long, so this will overflow the storage if you receive more than four bytes. If i is declared on the stack after msg, then it is likely that it is being overwritten by this overflow, and it happens to get overwritten by all zero bytes from the received packet.
Since msg is already a pointer, change your receive line to eliminate the superfluous indirection:
num_bytes = recv(i, msg, MAX_MSG_BYTE, 0);
Similarly, you may want to consider making the same change to the line
handle_request(arg, &msg)
if the handle_request function is not really expecting a pointer-to-pointer.
My first guess would be that sizeof(msg) < MAX_MSG_BYTE and when recv overflows msg it trashes i.
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 Have a typical client server C socket program.
SERVER:
if(ndp.cmd == 11)
{
//ack1 = 0;
puts("Query Command for Light 2");
pthread_mutex_lock(&lock);
// ..Some critical stuff
pthread_mutex_unlock(&lock);
printf("ID: %d, Level: %d\n", new.address, new.level);
ack1 = new.level; //This result is showing correct on server
ack1 = htonl(ack1);
send(client_sock, &ack1, sizeof(ack1), 0);
}
CLIENT:
printf("Query Actual level Light2\n");
dp.id = 2;dp.cmd = 11; dp.active = 0; dp.level = 0; dp.group = 0;
if( send(sock , &dp , sizeof(dp) , 0) < 0) { puts("Send failed"); }
sleep(1);
ret = recv(sock , &level1 , sizeof(level1) , 0);
printf("Number of bytes received: %d\n", ret); //Always gives 4
fflush(stdout);
printf("Light level %x\n", ntohl(level1) ); //This prints 0 (incorrect)
fflush(stdout);
sleep(5);
printf("Query Actual level Light2\n");
dp.id = 2;dp.cmd = 11; dp.active = 0; dp.level = 0; dp.group = 0;
if( send(sock , &dp , sizeof(dp) , 0) < 0) { puts("Send failed"); }
sleep(1);
ret = recv(sock , &level2 , sizeof(level2) , 0);
printf("Number of bytes received: %d\n", ret); // Always gives 4
fflush(stdout);
printf("Light level %x\n", ntohl(level2) ); //This prints correct value
fflush(stdout);
close(sock);
Expected output:
Light level 32 (hex value for 50);
Light level 32
Actual output:
Light level 0
Light level 32
So the problem is on same requests, 1st send from server is not received by client, but next recv() gives correct value.
Why is the data from 1st recv() getting lost, is it getting buffered and maybe I am getting the previous value in 2nd recv() ?
Please help.
Your assumption is not wrong. It may be buffered. Also note that when the receiver reads data faster than the sender does send it, some recv calls may read no data since the sender did not send any data yet. That could be the cause of what you're describing.
UPDATE: If you plan to always send/receive the same amount of data, for example a 20-byte packet containing what you defined as a command, then you can wrap your send and recv in a loop. This loop will write (or read) a single command at a time. You cannot assume a call to send or recv will succeed, so you MUST check for errors as #Joachim mentioned in comments. Another thing to note is that recv MAY read less bytes than the specified, so you may have to read multiple times in order to receive the complete command. The same applies to send.
You may use select/poll mechanism to check if there's new data has arrived to socket and waiting to be read properly. You can also check the amount of data has come to socket by invoking an ioctl call as the following:
{
int size = 0;
ioctl(socket, FIONREAD, &size);
if(size > 0)
{
// do recv operation(s)
}
}
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.
The Situation
After reading Unix Socket Programming, W.Richard Steven, I'm writing a P2P program in which the main thread creates thread pool in which five sub-threads live. it then monitors 50 sockets with kqueue(). when a event occurs in a specified socket (e.g, receiving data on the socket.), the main thread copies socket descriptor into a shared array and awakes one thread in the thread pool. the sub thread then processes a request from the socket. Also, I have protected the shared array using both mutex variable and conditional variable.
Question
The Author presents the source codes "server/serv08.c" and "server/pthread08.c" in the Section 30.12 and 30.13 in the book, respectively, as if there is no something wrong with this code. But, when I've written a code snippet similar to one author present, thread synchronization doesn't work well. Why does iput become equal to iget in main thread?
Code
--Global variable--
typedef struct tagThread_information
{
int sockfd;
} Thread_information;
Thread_information peer_fds[MAX_THREAD];
pthread_mutex_t peerfd_mutex;
pthread_cond_t peerfd_cond;
pthread_mutex_t STDOUT_mutex;
int iput;
int iget;
--Main thread--
void Wait_for_Handshake(download_session *pSession, int nMaxPeers)
{
struct kevent ev[50], result[50];
int kq, i, nfd;
int c = 1;
if( (kq = kqueue()) == -1)
{
fprintf(stderr, "fail to initialize kqueue.\n");
exit(0);
}
for(i = 0 ; i < nMaxPeers; i++)
{
EV_SET(&ev[i], pSession->Peers[i].sockfd, EVFILT_READ, EV_ADD, 0, 0, 0);
printf("socket : %d\n", (int)ev[i].ident);
}
// create thread pool. initialize mutex and conditional variable.
iput = 0;
iget = 0;
pthread_mutex_init(&STDOUT_mutex, NULL);
pthread_mutex_init(&peerfd_mutex, NULL);
pthread_cond_init(&peerfd_cond, NULL);
// Assume that MAX_THREAD is set to 5.
for(i = 0 ; i < MAX_THREAD; i++)
thread_make(i);
while(1)
{
nfd = kevent(kq, ev, nMaxPeers, result, nMaxPeers, NULL);
if(nfd == -1)
{
fprintf(stderr, "fail to monitor kqueue. error : %d\n", errno);
nMaxPeers = Update_peer(ev, pSession->nPeers);
pSession->nPeers = nMaxPeers;
continue;
}
for(i = 0 ; i < nfd; i++)
{
pthread_mutex_lock(&peerfd_mutex);
peer_fds[iput].sockfd = (int)result[i].ident;
if( ++iput == MAX_THREAD)
iput = 0;
if(iput == iget) // Here is my question.
{
exit(0);
}
pthread_cond_signal(&peerfd_cond);
pthread_mutex_unlock(&peerfd_mutex);
}
}
}
--sub thread--
void * thread_main(void *arg)
{
int connfd, nbytes;
char buf[2048];
for( ; ; )
{
/* get socket descriptor */
pthread_mutex_lock(&peerfd_mutex);
while( iget == iput)
pthread_cond_wait(&peerfd_cond, &peerfd_mutex);
connfd = peer_fds[iget].sockfd;
if ( ++iget == MAX_THREAD )
iget = 0;
pthread_mutex_unlock(&peerfd_mutex);
/* process a request on socket descriptor. */
nbytes = (int)read(connfd, buf, 2048);
if(nbytes == 0)
{
pthread_mutex_lock(&STDOUT_mutex);
printf("\n\nthread %ld, socket : %d, nbytes : %d\n\n\n", (long int)pthread_self(), connfd, nbytes);
printf("socket closed\n\n");
pthread_mutex_unlock(&STDOUT_mutex);
close(connfd);
continue;
}
else if(nbytes == -1)
{
close(connfd);
pthread_mutex_lock(&STDOUT_mutex);
printf("\n\nthread %ld, socket : %d, nbytes : %d\n\n\n", (long int)pthread_self(), connfd, nbytes);
perror("socket error : ");
write(STDOUT_FILENO, buf, nbytes);
printf("\n\n\n\n");
pthread_mutex_unlock(&STDOUT_mutex);
continue;
}
pthread_mutex_lock(&STDOUT_mutex);
printf("\n\nthread %ld, socket : %d, nbytes : %d\n\n\n", (long int)pthread_self(), connfd, nbytes);
write(STDOUT_FILENO, buf, nbytes);
printf("\n\n\n\n");
pthread_mutex_unlock(&STDOUT_mutex);
}
}
In your main thread:
if( ++iput == MAX_THREAD)
iput = 0;// so iput is 0 --> MAX_THREAD
And in your sub thread:
if ( ++iget == MAX_THREAD )
iget = 0;// So iget is 0 --> MAX_THREAD
Since the sub thread and the main thread runs at the "same time",and they are golbal values .the iput maybe equare to iget sometime.
From "UNIX Network Prgramming Volume 1, 2nd Edition", chapter 27.12, page 757, from the annotations to the lines 27-38 of server/serv08.c:
We also check that the iput index has not caught up with the iget index, which indicates that our array is not big enough.
For reference the lines mentioned above (take from here):
27 for ( ; ; ) {
28 clilen = addrlen;
29 connfd = Accept(listenfd, cliaddr, &clilen);
30 Pthread_mutex_lock(&clifd_mutex);
31 clifd[iput] = connfd;
32 if (++iput == MAXNCLI)
33 iput = 0;
34 if (iput == iget)
35 err_quit("iput = iget = %d", iput);
36 Pthread_cond_signal(&clifd_cond);
37 Pthread_mutex_unlock(&clifd_mutex);
38 }
What you have there is a typical circular buffer implementation.
The head and tail pointers/indices point to the same location when the circular buffer is empty. You can see this being tested in the code while (iget == iput) ... which means "while the queue is empty ...".
If, after an insertion at the head of a circular buffer, head points to tail, that is a problem. The buffer has overflowed. It is a problem because now the buffer now looks empty even though it is full.
That is to say, one unused location is reserved in the buffer; if the buffer has 4096 entries, we can only fill 4095. If we fill 4096, it then we have overflow: it looks like an empty circular buffer.
(We could use all 4096 locations if we allowed the index to go from 0 to 8192, using an extra bit to resolve the ambiguity, so that instead of wrapping to zero past 4095, the pointers would keep going to 4096 ... 8191. We would have to remember to access the array modulo 4096, of course. It's a big cost in complexity for the sake of recovering one wasted element.)
It looks like the code bails on circular buffer overflow because it is structured such that this condition cannot happen, and so it constitutes an internal error. The circular buffer overflows when there are too many descriptors being passed from the producer to the consumer in a single bout.
In general, circular buffer code cannot just bail when the buffer is full. Either the insertion operation has to balk and return an error, or it has to block for more space. So this is a special case based on assumptions particular to the example program.
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?