views:

614

answers:

5

Hi, I have a small program that sends and receives data from server and client and vice-versa. Everything works fine, but I can't see received messages in both sides and it is always 0 bytes. It doesn't give any compile error but doesnt work the way I wanted to. Can you please have a look at this, where I am doing wrong ? Thanks

// client

#include <stdio.h>
#include <unistd.h> 
#include <stdlib.h> 
#include <string.h>
#include <time.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>

int main(int argc, char* argv[])
{
    int sockfd;

    struct addrinfo hints, *servinfo, *p;
    int rv;
    int numbytes;
    char* hostname = "localhost";
    char* server = "localhost";

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    if ((rv = getaddrinfo(hostname, "5000", &hints, &servinfo)) != 0)
    {
     fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
     return 0;
    }


    // loop through all the results and make a socket
    for(p = servinfo; p != NULL; p = p->ai_next) 
    {
     if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) 
     {
         perror("client: socket");
         continue;
     }

     if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) 
     {
         close(sockfd);
         perror("client: connect");
         continue;
     }
     break;
    }
    if (p == NULL) 
    {
     fprintf(stderr, "client: failed to bind socket\n");
     return 2;
    }

    char message[] = "hi";
    if ((numbytes = send(sockfd, message, 2, 0)) == -1) 
    {
     perror("client: send");
     exit(1);
    }

    int numbytesRecv;
    char buf[100];
    if ((numbytesRecv = recv(sockfd, buf, 99, 0)) == -1) 
    {
     perror("client: recv");
     exit(1);
    }

    freeaddrinfo(servinfo);
    printf("client: sent %d bytes to %s\n", numbytes, server);
    printf("client: received %d bytes from %s\n", numbytesRecv, server);
    buf[numbytesRecv] = '\0';
    printf("client: message received is %s\n",buf);
    close(sockfd);
    return 0;
}

// server

#include   <stdio.h>
#include   <stdlib.h>
#include   <unistd.h>
#include   <errno.h>
#include   <string.h>
#include   <sys/types.h>
#include   <sys/socket.h>
#include   <netinet/in.h>
#include   <arpa/inet.h>
#include   <netdb.h>
#define MYPORT "5000"     // the port users will be connecting to
#define MAXBUFLEN 100
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
     if (sa->sa_family == AF_INET) {
          return &(((struct sockaddr_in*)sa)->sin_addr);
     }
     return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(void)
{
    int sockfdTCP;
    struct addrinfo hintsTCP, *servinfoTCP, *pTCP;
    int rv;
    int numbytes;
    struct sockaddr_storage their_addr;
    char buf[MAXBUFLEN];

    size_t addr_len;
    char s[INET6_ADDRSTRLEN];

    memset(&hintsTCP, 0, sizeof hintsTCP);
    hintsTCP.ai_family = AF_UNSPEC;
    hintsTCP.ai_socktype = SOCK_STREAM;
    hintsTCP.ai_flags = AI_PASSIVE;

    if ((rv = getaddrinfo(NULL, MYPORT, &hintsTCP, &servinfoTCP)) != 0) {
     fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
     return 1;
    }

    // loop through all the results and bind to the first we can for TCP socket
    for(pTCP = servinfoTCP; pTCP != NULL; pTCP = pTCP->ai_next) 
    {
     if ((sockfdTCP = socket(pTCP->ai_family, pTCP->ai_socktype,pTCP->ai_protocol)) == -1) 
     {
      perror("listener: socket");
      continue;
     }

     if (bind(sockfdTCP, pTCP->ai_addr, pTCP->ai_addrlen) == -1) 
     {
      close(sockfdTCP);
      perror("listener: bind");
      continue;
     }
     break;
    }

    if (pTCP == NULL) 
    {
     fprintf(stderr, "listener: failed to bind socket\n");
     return 2;
    }
    freeaddrinfo(servinfoTCP);

    printf("listener: waiting to recvfrom...\n");
    addr_len = sizeof their_addr;

    const int BACKLOG = 10;
    if (listen(sockfdTCP, BACKLOG) == -1) {
     perror("listen");
     exit(1);
    }

    socklen_t sin_size;
    int new_fd;
    sin_size = sizeof their_addr;
    new_fd = accept(sockfdTCP, (struct sockaddr *)&their_addr, &sin_size);
    printf("I am here\n");
    if (new_fd == -1) 
    {
        perror("accept");
    }

    if ((numbytes = recv(new_fd, buf, MAXBUFLEN, 0) == -1)) 
{
 perror("recv");
 exit(1);
}

char* msg = " hi i am server";
int numbytesSend;
if ((numbytesSend = send(new_fd, msg,strlen(msg), 0) == -1)) 
{
 perror("recv");
 exit(1);
}

inet_ntop(their_addr.ss_family,get_in_addr((struct sockaddr *)&their_addr), s, sizeof s);
printf("server: got connection from %s\n", s);

printf("listener: packet is %d bytes long\n", numbytes);
buf[numbytes] = '\0';
printf("listener: packet contains : %s\n", buf);

close(sockfdTCP);
close(new_fd);
return 0;

}

// output client

./clientTCP 
client: sent 2 bytes to localhost
client: received 0 bytes from localhost
client: message received is

// output server

./serverTCP 
listener: waiting to recvfrom...
I am here
server: got connection from 127.0.0.1
listener: packet is 0 bytes long
listener: packet contains :
+2  A: 

It's been a while since I've done raw sockets programming, but I think there's something fishy with your recv() calls. IIRC, recv() blocks until it reads the full size of the buffer or the connection is closed. Since neither end sends enough data for it to fill the buffer, and the socket doesn't get closed until after the recv() calls, I think one or both of your client/server should hang. Since they do not, one of two things is happening. Either the sockets are configured for non-blocking mode and you need to configure them to block, or something is closing the socket. I'm sorry I can't offer more detailed help than that, but hopefully it will point you in the right direction. You may also want to investigate the shutdown() call to use on sockets so that you don't close them before all the data in the buffer is sent. Not sure if that has anything to do with your problem.

rmeador
recv() can return before it reads the full size of the buffer, i.e. a short read occurs. However, the return values of zero implies the socket was shutdown. That is a bit odd. I agree that some blocking should have occurred.
Void
+2  A: 

EDIT: I just tested on OS X. Your code works for me. Now, I really think you must have something consuming your bytes. Kill your processes and do:

$ netstat -na | grep 5000

To see if you have anything listening on port 5000. If so, you need to kill the server.

Also, make sure the super server (inetd/xinetd) isn't spawning something to handle data on port 5000.

Rob Jones
+1  A: 

It looks like you're being bitten by Nagle's Algorithm. Try setting TCP_NODELAY to allow small packets to be sent right away.

Note that for production code you should profile before deciding to disable the Nagle Algorithm.

Void
When I try to compile using your suggestion, I get this compile error,serverTCP.c: In function ‘main’:serverTCP.c:53: error: ‘TCP_NODELAY’ undeclared (first use in this function)serverTCP.c:53: error: (Each undeclared identifier is reported only onceserverTCP.c:53: error: for each function it appears in.)Do I need to use any extra libraries other than lsocket.
seg.server.fault
@seg.server.fault: You need to include <netinet/tcp.h>, as described here: http://www.opengroup.org/onlinepubs/000095399/basedefs/netinet/tcp.h.htmlHTH!
Void
+7  A: 

Your problem is this line in the server:

if ((numbytes = recv(new_fd, buf, MAXBUFLEN, 0) == -1))

It should be:

if ((numbytes = recv(new_fd, buf, MAXBUFLEN, 0)) == -1)

This will allow numbytes to be properly assigned, which allows

buf[numbytes] = '\0';

to do what you intend and lets

printf("listener: packet contains : %s\n", buf);

print what you want.

Same deal with

if ((numbytesSend = send(new_fd, msg, strlen(msg), 0) == -1))

but the bug doesn't manifest itself in the example program.

Duck
+1 - good catch
Nikolai N Fetissov
+1 - Indeed a nice catch.
Void
A: 

hi to all... Sorry to ask here a question not directly relatd to this thread...

Above example create connection for only single req and server then sends response...

to send req again to server we have to establish the connection again...

How can i get rid of this.. I need to get connected to server only once and able to send and recieve data asynchronously...

using asynch sockets i feel dis thing is achievable.. but I ahvn't found simple,easy to understand example to implement asynch sockts..

can anybody help me out of this.. Plz mail me some useful stuff if u hav to [email protected] Thanks in advance..