I have implemented the client server using socket programming in C on Unix OS. I have used the non blocking socket at client end. I want to implement the two way communication. But its working only with one way i.e. Client can read and write the data on server, but server can not read or write data on client.
Client
nread = recv(sock, ptr, nleft, MSG_DONTWAIT))
send(sock, ptr, nleft, 0))
Server
recv(sock, ptr, nleft, MSG_DONTWAIT))
SockWrite(sock, Message, dataLength)
Server is always facing problem in reading. Can any one explain me why and how to get rid of this?
Await for socket ready for reading or writing using select() call.
code samples
static void SetNonBlock(const int nSock, bool bNonBlock)
{
int nFlags = fcntl(nSock, F_GETFL, 0);
if (bNonBlock) {
nFlags |= O_NONBLOCK;
} else {
nFlags &= ~O_NONBLOCK;
}
fcntl(nSock, F_SETFL, nFlags);
}
...
SetNonBlock(sock, true);
...
int code = recv(sock, buf, len_expected, 0);
if(code > 0) {
here got all or partial data
} else if(code < 0) {
if((errno != EAGAIN) && (errno != EINPROGRESS) ) {
here handle errors
}
otherwise may try again
} else if(0 == code) {
FIN received, close the socket
}
What is the return code to recv? Have you set the recv socket to non-blocking? In that case you are probably seeing EAGAIN, and you need to select() etc, or go back to blocking. I would not recommend ever ignoring return values to system calls.
Related
So I'm trying to do the following:
I have two participants (let's call them A and B) communicating via TCP socket (send() and recv()). A is sending a counter and a random Nonce, B is just responding with that same message it gets. A then checks if the response matches the sent packet and if yes, it increments the counter and repeats.
This is a code snippet illustrating what A does at the moment:
send(sock, payload, strlen(payload), 0);
struct timeval t_out;
t_out.tv_sec = 0;
t_out.tv_usec = 5000;
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,&t_out,sizeof(t_out)) <0)
int len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
if (len < 0)
{
print("Timeout reached, recv failed: errno %d", errno);
}
else
{
rx_buffer[len] = 0;
if(strncmp(rx_buffer, payload, payload_len) == 0)
{
pack_nr++;
}
}
Now I'm encountering one problem.
Let's say B, for some reason, has a delay in responding. This causes something like that:
A sends something like "1xyz"
B has a delay ......
A times out and resends something like "1abc"
B's first response ("1xyz") reaches A, A decides that this is the wrong payload
B's second response ("1abc") reaches A too, but A is only executing one recv() and it's unseen for now
A resends something like "1uvw"
A reads "1abc" from recv() and again decides that this is the wrong payload
B's third response ("1uvw") reaches A, and so on and on
So what I'd like to do is to put a recv() in a loop, so that in step 5, A would first look for another response from B until the timeout is reached.
So is there clever way to do this? I was thinking about something like
send(sock, payload, strlen(payload), 0);
int flag = 0;
gettimeofday(&start_time, NULL);
while((tx_time < start_time + timeout) && flag = 0)
{
gettimeofday(&tx_time, NULL);
recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
if(rx_buffer is okay)
{
flag = 1;
}
wait_a_bit();
}
if(flag == 1) pack_nr++;
"... B is just responding with that same message it gets. A then checks if the response matches the sent packet ..."
You have a code problem and a terminology problem.
First, the terminology problem: Don't say "matches the sent packet". The data can be sent in one packet or ten packets, TCP doesn't care. You don't receive packets, you receive data that may be split or combined across packets as TCP wishes. It really helps (trust me) to be very precise in your use of words. If you mean a message, say "message". If you mean data, say "data". If you mean a datagram, say "datagram".
Unfortunately, your code problem is enormous. You want B to respond to A with the same message it received. That means you need a protocol that sends and receives messages. TCP is not a message protocol. So you need to implement a message protocol and write code that actually sends and receives messages.
If A write "foobar", B might receive "foobar" or it might first receive "foo" and then later "bar". If A writes "foo" then "bar", B might receive "foobar" or "f" and then "oobar". That's TCP. If you need a message protocol, you need to implement one.
First off, you are not checking for a timeout correctly. recv() could fail for any number of reasons. You need to check errno (or WSAGetLastError() on Windows) to find out WHY it failed. But even if it did actually fail due to timeout, TCP is a byte stream, the delayed data may still show up (especially since 5000 microseconds (0.005 seconds) is way too short a timeout to reliably use for TCP network traffic), but your sender would have moved on. The only sensible thing to do if a timeout occurs in TCP is to close the connection, since you don't know the state of the stream anymore.
In your situation, you are basically implementing an ECHO protocol. Whatever the sender sends just gets echoed back as-is. As such, if you send 4 bytes (which you are not verifying, BTW), then you should keep reading until 4 bytes are received, THEN compare them. If any failure occurs in that process, immediately close the connection.
int sendAll(int sock, void *data, int len)
{
char *ptr = (char*) data;
while (len > 0) {
int sent = send(sock, ptr, len, 0);
if (sent < 0) {
if (errno != EINTR)
return -1;
}
else {
ptr += sent;
len -= sent;
}
}
return 0;
}
int recvAll(int sock, void *data, int len)
{
char *ptr = (char*) data;
while (len > 0) {
int recvd = recv(sock, ptr, len, 0);
if (recvd < 0) {
if (errno != EINTR)
return -1;
}
else if (recvd == 0) {
return 0;
}
else {
ptr += recvd;
len -= recvd;
}
}
return 1;
}
...
int payload_len = strlen(payload);
if (sendAll(sock, payload, payload_len) < 0)
{
// error handling
close(sock);
}
else
{
struct timeval t_out;
t_out.tv_sec = 5;
t_out.tv_usec = 0;
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &t_out, sizeof(t_out)) < 0)
{
// error handling
close(sock);
}
else
{
int res = recvAll(sock, rx_buffer, payload_len);
if (res < 0)
{
if (errno == EAGAIN || errno == EWOULDBLOCK)
print("Timeout reached");
else
print("recv failed: errno %d", errno);
close(sock);
}
else if (res == 0)
{
print("disconnected");
close(sock);
}
else
{
if (memcmp(rx_buffer, payload, payload_len) == 0)
{
print("data matches");
pack_nr++;
}
else
print("data mismatch!");
}
}
}
I want to use non-blocking API of recv but it doesn't work after 64KB data and give error: Resource temporarily unavailable. So I use if(error == EAGAIN) but it stuck on receive because no data is available.
while(true) {
ret = recv(csd, buf, size, MSG_DONTWAIT);
if(errno == EAGAIN) {
continue;
}
if (ret < 0) {
perror("Error in receive\n");
close(csd);
exit(EXIT_FAILURE);
} else if (ret == 0) {
fprintf(stderr, "client disconnected\n");
close(csd);
} else {
return buf;
}
}
By default the socket uses a 64k buffer internally and then the kernel refuses to accept more data. So recv() can return at most 64kb of data without waiting.
You could change the buffer size for the socket (man 7 socket, SO_RCVBUF) or use a loop around select and recv to read it in multiple goes into a larger buffer as it becomes available.
I was going through nanomsg usage for IPC and wanted to use SURVEY-archetype architecture described here.In this, processes run as client and server and exchange data. Now server has following code (also listed in the provided link):
int server (const char *url)
{
int sock = nn_socket (AF_SP, NN_SURVEYOR);
assert (sock >= 0);
assert (nn_bind (sock, url) >= 0);
sleep(1); // wait for connections
int sz_d = strlen(DATE) + 1; // '\0' too
printf ("SERVER: SENDING DATE SURVEY REQUEST\n");
int bytes = nn_send (sock, DATE, sz_d, 0);
assert (bytes == sz_d);
while (1)
{
char *buf = NULL;
int bytes = nn_recv (sock, &buf, NN_MSG, 0);
if (bytes == ETIMEDOUT) break;
if (bytes >= 0)
{
printf ("SERVER: RECEIVED \"%s\" SURVEY RESPONSE\n", buf);
nn_freemsg (buf);
}
}
return nn_shutdown (sock, 0);
}
Since socket type is NN_SURVEYOR, the while-loop doesn't wait at nn_recv. For client, socket type is NN_RESPONDENT and so, while loop in client waits at nn_recv.
Now since this while loop runs continuously and infinitely, the CPU usage shoots up to 99%. Can you please tell me that is there any other way to make survey architecture using nanomsg.
Try adding yield() call in the end of loop if nothing was received.
I'm trying to write a server in C, with I/O non-blocking because sometimes it goes down for flood requests.
Looking around, I've notice that I/O non-blocking can solve my problem.
Reading the Beej guide, I've implemented the recvtimeout function, that set a timeout to handle data from a client.
People told me I have to use the select to avoid this problem, but I used it already in the function recvtimeout:
int Server::recvtimeout(int s, char *buf, int len, int timeout)
{
//Check if non-blocking
fcntl(s, F_SETFL, O_NONBLOCK);
int flags = fcntl(s, F_GETFD);
if ((flags & O_NONBLOCK) == O_NONBLOCK) {
fprintf(stderr, "nonblocking active");
}
else {
fprintf(stderr, "nonblocking not active");
}
//End check
fd_set fds;
int n;
struct timeval tv;
// set up the file descriptor set
FD_ZERO(&fds);
FD_SET(s, &fds);
// set up the struct timeval for the timeout
tv.tv_sec = timeout;
tv.tv_usec = 0;
// wait until timeout or data received
n = select(s+1, &fds, NULL, NULL, &tv);
if (n == 0){
return -2; // timeout!
}
if (n == -1){
return -1; // error
}
// data must be here, so do a normal recv()
return recv(s, buf, len, 0);
}
So, I've added a piece of code that show me if NONBLOCK is set or not, but never I read nonblocking active, so in my code nonblocking is not active.
How can I mod my code to enable this?
The problem is when I read a string from a client and have a code like this:
char headerstring[512];
memset(headerstring,0,512);
if(this->recvtimeout(client_fd,headerstring,sizeof(headerstring),10) < 0){
close(client_fd);
}
All works fine, but with a flooder that close the connection during the transaction, the server goes down.
I've tried try-catch and any other things...but nothing.
The normal way to set a socket to non-blocking is
int x;
x=fcntl(s,F_GETFL,0);
fcntl(s,F_SETFL,x | O_NONBLOCK);
In your code you are getting the flags using
int flags = fcntl(s, F_GETFD);
whereas you should be doing as
x=fcntl(s,F_GETFL,0);
So, non-blocking may actually be getting enabled on your socket.
There are a couple of things:
After select() call:
if(n < 0) continue;
if(FD_ISSET(s, &fds)) { //check if Socket ready for reading
FD_CLR(s, &fds); // Clear for next time
// call recv()
}
Set socket as non-blocking like this:
/* set socket as non-blocking */
int x = fcntl(s, F_GETFL, 0);
fcntl(s, F_SETFL, x | O_NONBLOCK);
I basically have a server set up and I'm accepting new clients(UNIX) and i'm using select() command to wait for activity on file descriptor but I'm not sure how to write from the clients side and then read it on the servers side
FD_ZERO(&readfds);
FD_SET(server_sockfd, &readfds);
FD_SET(STDIN_FILENO, &readfds);
while (1) {
testfds = readfds;
select(4 + MAXCLIENTS, &testfds, NULL, NULL, NULL);
for (fd = 0; fd < 4 + MAX_CLIENTS; fd++) {
if (FD_ISSET(fd, &testfds)) {
if (fd == server_sockfd) { /* new connection request */
client_sockfd = accept(server_sockfd, NULL, NULL);
if (num_clients < MAXCLIENTS) {
FD_SET(client_sockfd, &readfds);
num_clients++;
} else {
sprintf(message, "XSorry, too many clients. Try again later.\n");
write(client_sockfd, message, strlen(message));
close(client_sockfd);
}
} else if (fd == STDIN_FILENO) {
fgets(kb_message, BUFSIZ + 1, stdin);
if (strcmp(kb_message, "quit\n") == 0) {
sprintf(message, "XServer is shutting down.\n");
for (fd2 = 4; fd2 < 4 + MAX_CLIENTS; fd2++) {
if (FD_ISSET(fd2, &readfds)) {
write(fd2, message, strlen(message));
close(fd2);
}
}
close(server_sockfd);
exit(EXIT_SUCCESS);
} else {
sprintf(message, "M%s", kb_message);
for (fd2 = 4; fd2 < 4 + MAX_CLIENTS; fd2++)
if (FD_ISSET(fd2, &readfds))
write(fd2, message, strlen(message));
}
} else { /* client leaving */
close(fd);
FD_CLR(fd, &readfds);
num_clients--;
}
}
}
}
How would I handle write request from clients and then write back to them, would it be under "else" and how can I check if client is exiting or writing.
Thanks
The most common mistake with select(2) is not re-initializing the descriptor sets, since second, third, and forth arguments are input-output parameters.
Setup an fd_set, for reading before the outer loop, add listening socket descriptor to it, enter the loop, make a copy of the this fd_set and give the copy to select(2). When new connection arrives, add its descriptor to the original fd_set. Same for closed socket (error or EOF on read(2)) - remove the descriptor from the original fd_set.
Hope this helps.
You are correct in thinking you need the read code in your 'else' block. If a file descriptor triggers and it isn't stdin or the 'connect' descriptor, then it is one of your clients attempting to send you data. When one of those file descriptors is triggered in the select, you need to call 'read' on that descriptor to read the data into the buffer. The read command will return you the number of bytes read. If this is a positive number, then it indicates the client has sent you data. If it is zero, then that indicates that the client has ended the TCP connection to your server.
The else block will look something like:
else
{
//Existing connection has data for us to read
if((nBytes = read(fd, buffer, MAXBUFFER)) <= 0)
{
if(nBytes == 0)
{
//Actually, its sending us zero bytes, connection closed
printf("Socket %d hung up\n", fd;
}
else
printf ("Read Error"\n)
}
Also, Follow Nikolai N Fetissov's advice above and make sure that when client's connect you store their fd in a permanent fd_set structure, as the one you are using is being modified by the select call.
Your problem might be that you have a variable called read. It's going to mask one of hte functions you need to use - the read() system call to get data out of the socket. The client puts it in with write(). You might also want to check the return value from select(), which will tell you how many of the file descriptors are ready for reading. Then you can check which ones using FD_ISSET(). It looks like you're doing that part already (except you seem to be checking the wrong variable?)... just call read() on that file descriptor to get out the data the client wrote.
else
{
bzero(buf,100);
n=read(i,buf,100); // Read the client message
buf[n]='\0';
if(n==0) // Check the client is closed or not
{
printf("%d is closed\n",i);
close(i);
FD_CLR(i, &master);
if(i==fdmax)
fdmax--;
}
else
{
n=strlen(buf);
write(1,buf,n);
fflush(stdout);
write(1,"Enter the message\n",18);
bzero(buf,100);
read(0,buf,100);
buf[n]='\0';
write(i,buf,n);
fflush(stdout);
}
}
Notes:
After accept the client, Add the client in the fd set.
Then read the message from the client
If the message is equal to 0, then the client is closed.
If you want to send the message to the client, using the client fd, you can send to the client