Thread: Socket programming - send loop

  1. #1
    Registered User lantzvillian's Avatar
    Join Date
    Sep 2010
    Posts
    44

    Socket programming - send loop

    Hi all,

    I have a simple client/server setup running on my localhost that is currently set to be in a loop and to send a tcp packet containing "This is the message to send" to the server.

    I'd like to have the client send the message once, wait (kind of like a keep alive) and send it again. I am noticing that it sends a bunch of packets at once and the server doesn't necessarily know what to do with it. The server echoing that the client has been sending traffic is a bit wacky.

    Any ideas to get me going?

    Client.c
    Code:
    #include <stdio.h>
    #include <netdb.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <errno.h>
    #include <stdlib.h>
    #include <strings.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    
    #define SERVER_TCP_PORT		7000	// Default port
    #define BUFLEN			1024  	// Buffer length
    
    int main (int argc, char **argv)
    {
      int n, bytes_to_read;
      int sd, port;
      struct hostent	*hp;
      struct sockaddr_in server;
      char  *host, *bp, rbuf[BUFLEN], **pptr;
      char *sbuf="This is a message to send\n\r";
      char str[16];
      
      switch(argc)
      {
        case 2:
          host =	argv[1];	// Host name
          port =	SERVER_TCP_PORT;
          break;
        case 3:
          host =	argv[1];
          port =	atoi(argv[2]);	// User specified port
          break;
        default:
          fprintf(stderr, "Usage: %s host [port]\n", argv[0]);
          exit(1);
      }
      
      // Create the socket
      if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
      {
        perror("Cannot create socket");
          exit(1);
      }
      bzero((char *)&server, sizeof(struct sockaddr_in));
      server.sin_family = AF_INET;
      server.sin_port = htons(port);
      if ((hp = gethostbyname(host)) == NULL)
      {
        fprintf(stderr, "Unknown server address\n");
        exit(1);
      }
      bcopy(hp->h_addr, (char *)&server.sin_addr, hp->h_length);
      
      // Connecting to the server
      if (connect (sd, (struct sockaddr *)&server, sizeof(server)) == -1)
      {
        fprintf(stderr, "Can't connect to server\n");
        perror("connect");
        exit(1);
      }
      printf("Connected:    Server Name: %s\n", hp->h_name);
      pptr = hp->h_addr_list;
      printf("\t\tIP Address: %s\n", inet_ntop(hp->h_addrtype, *pptr, str, sizeof(str)));
      
      while(1){
        
        printf("Transmiting:\n");
        
        for(;;) {
          // Transmit data through the socket
          send(sd, sbuf, strlen(sbuf), 0);
          sleep(12);	
        }
    
      }
      fflush(stdout);
      close (sd);
      return (0);
    }
    server.c
    Code:
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <stdlib.h>
    #include <strings.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    
    #define SERVER_TCP_PORT 7000	// Default port
    #define BUFLEN	80		//Buffer length
    #define TRUE	1
    #define LISTENQ	5
    #define MAXLINE 4096
    
    // Function Prototypes
    static void SystemFatal(const char* );
    
    int main (int argc, char **argv)
    {
    	int i, maxi, nready, bytes_to_read, arg;
    	int listen_sd, new_sd, sockfd, client_len, port, maxfd, client[FD_SETSIZE];
    	struct sockaddr_in server, client_addr;
    	char *bp, buf[BUFLEN];
       	ssize_t n;
       	fd_set rset, allset;
    
    	switch(argc)
    	{
    		case 1:
    			port = SERVER_TCP_PORT;	// Use the default port
    		break;
    		case 2:
    			port = atoi(argv[1]);	// Get user specified port
    		break;
    		default:
    			fprintf(stderr, "Usage: %s [port]\n", argv[0]);
    			exit(1);
    	}
    
    	// Create a stream socket
    	if ((listen_sd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    		SystemFatal("Cannot Create Socket!");
    	
    	// set SO_REUSEADDR so port can be resused imemediately after exit, i.e., after CTRL-c
            arg = 1;
            if (setsockopt (listen_sd, SOL_SOCKET, SO_REUSEADDR, &arg, sizeof(arg)) == -1)
                    SystemFatal("setsockopt");
    
    	// Bind an address to the socket
    	bzero((char *)&server, sizeof(struct sockaddr_in));
    	server.sin_family = AF_INET;
    	server.sin_port = htons(port);
    	server.sin_addr.s_addr = htonl(INADDR_ANY); // Accept connections from any client
    
    	if (bind(listen_sd, (struct sockaddr *)&server, sizeof(server)) == -1)
    		SystemFatal("bind error");
    	
    	// Listen for connections
    	// queue up to LISTENQ connect requests
    	listen(listen_sd, LISTENQ);
    
    	maxfd	= listen_sd;	// initialize
       	maxi	= -1;		// index into client[] array
    
    	for (i = 0; i < FD_SETSIZE; i++)
               	client[i] = -1;             // -1 indicates available entry
     	FD_ZERO(&allset);
       	FD_SET(listen_sd, &allset);
    
    
    	while (TRUE)
    	{
       		rset = allset;               // structure assignment
    		nready = select(maxfd + 1, &rset, NULL, NULL, NULL);
    
          		if (FD_ISSET(listen_sd, &rset)) // new client connection
          		{
    			client_len = sizeof(client_addr);
    			if ((new_sd = accept(listen_sd, (struct sockaddr *) &client_addr, &client_len)) == -1)
    				SystemFatal("accept error");
    			
                            printf(" Remote Address:  %s\n", inet_ntoa(client_addr.sin_addr));
    
                            for (i = 0; i < FD_SETSIZE; i++)
    			if (client[i] < 0)
                		{
    				client[i] = new_sd;	// save descriptor
    				break;
                		}
    			if (i == FD_SETSIZE)
             		{
    				printf ("Too many clients\n");
                			exit(1);
        			}
    
    			FD_SET (new_sd, &allset);     // add new descriptor to set
    			if (new_sd > maxfd)
    				maxfd = new_sd;	// for select
    
    			if (i > maxi)
    				maxi = i;	// new max index in client[] array
    
    			if (--nready <= 0)
    				continue;	// no more readable descriptors
         		 }
    
    		for (i = 0; i <= maxi; i++)	// check all clients for data
         		{
    			if ((sockfd = client[i]) < 0)
    				continue;
    
    			if (FD_ISSET(sockfd, &rset))
             		{
    
    				for(;;) {
    				bp = buf;
    				bytes_to_read = BUFLEN;
    				while ((n = read(sockfd, bp, bytes_to_read)) > 0)
    				{
    					bp += n;
    					bytes_to_read -= n;
    				}
    				
    				printf("%s",buf);
    				
    				}
    
    
    				if (n == 0) // connection closed by client
                			{
    					printf(" Remote Address:  %s closed connection\n", inet_ntoa(client_addr.sin_addr));
    					close(sockfd);
    					FD_CLR(sockfd, &allset);
                   				client[i] = -1;
                			}
    									            				
    				if (--nready <= 0)
                				break;        // no more readable descriptors
    			}
         		 }
       	}
    	return(0);
    }
    
    // Prints the error stored in errno and aborts the program.
    static void SystemFatal(const char* message)
    {
        perror (message);
        exit (EXIT_FAILURE);
    }

  2. #2
    Registered User lantzvillian's Avatar
    Join Date
    Sep 2010
    Posts
    44
    Well I the client sending a data regularly every 10 seconds - as seen per Wireshark, but I am having trouble with the server recieve loop.

    Code:
    		  if (FD_ISSET(sockfd, &rset))
    		  {
    		    
    		    for(;;) {
    
    		      bp = buf;
    		      bytes_to_read = strlen("This is a message to send\n\r");
    
    		      while ((n = read(sockfd, bp, bytes_to_read)) > 0)
    		      {
    			  bp += n;
    			  bytes_to_read -= n;
    		      }
    		      printf("%s",buf);
    		      sleep(10);
    		      
    		      	    if (n == 0) // connection closed by client
    		    {
    				  printf(" Remote Address:  %s closed connection\n", inet_ntoa(client_addr.sin_addr));
    				  close(sockfd);
    				  FD_CLR(sockfd, &allset);
    				  client[i] = -1;
    		     }
    		      
    		    }
    	
    		    if (--nready <= 0)
    			 break;        // no more readable descriptors
    		 }
    If I remve the connection closed by client, I get a connection that will not end. If I put the n == 0 into the loop like above, the server sends a FIN packet back to the client.

    The connection is supposed to be neverending and the packet being sent - is to be like a keep alive once the connection is going. Ideas?

  3. #3
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    The only way out of your while n=read loop is for n to be zero, right? So I don't know why you're surprised that the if n==0 bit happens always.

  4. #4
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    I'm guessing you're trying to keep some machine from going into standby....

    While a server client pair can do that --and it's certainly an interesting exercise-- you can do that far more easily with UDP... just send a packet with 0 data to port 9 (The "discard" port) every 5 minutes or so... or on pre-win7 machines you can just ping it.

  5. #5
    Registered User lantzvillian's Avatar
    Join Date
    Sep 2010
    Posts
    44
    CommonTater - you got it, but I think I am going ot stick with TCP.

    If I put in the n == 0 statement, a sleep(1) and check again.. that should work no?

  6. #6
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    TCP has connect and disconnect signals... you should look at some of the tutorials out there for the best method of doing this...

    Code wise... I wouldn't expect a byte count to accurately reflect the status of a TCP connection. Remember these connections are buffered and packets can be delayed. Also, read() is a blocking call that won't return until something is received so it may be somewhat unreliable at knowing the active status of a connection... it may just hang. This would require experimentation.

    Now I'm curious why you want/need to prevent standby...

    You may also want to investigate "wake on lan" protocals that might serve you better.... Google "magic packets"... you can even wake a machine from power off, if you use them correctly.

  7. #7
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Quote Originally Posted by lantzvillian View Post
    Well I the client sending a data regularly every 10 seconds - as seen per Wireshark, but I am having trouble with the server recieve loop.

    Code:
    		  if (FD_ISSET(sockfd, &rset))
    		  {
    		    
    		    for(;;) {
    
    		      bp = buf;
    		      bytes_to_read = strlen("This is a message to send\n\r");
    
    		      while ((n = read(sockfd, bp, bytes_to_read)) > 0)
    		      {
    			  bp += n;
    			  bytes_to_read -= n;
    		      }
    		      printf("%s",buf);
    		      sleep(10);
    		      
    		      	    if (n == 0) // connection closed by client
    		    {
    				  printf(" Remote Address:  %s closed connection\n", inet_ntoa(client_addr.sin_addr));
    				  close(sockfd);
    				  FD_CLR(sockfd, &allset);
    				  client[i] = -1;
    		     }
    		      
    		    }
    	
    		    if (--nready <= 0)
    			 break;        // no more readable descriptors
    		 }
    If I remve the connection closed by client, I get a connection that will not end. If I put the n == 0 into the loop like above, the server sends a FIN packet back to the client.

    The connection is supposed to be neverending and the packet being sent - is to be like a keep alive once the connection is going. Ideas?
    I'm pretty sure you don't what that for(; ; ) loop in there. You're stuck processing only one of your clients indefinitely, even if there's no data left and they close the connection. Also, the while loop for reading shouldn't be in there. You ask for BUFSIZ data on the first read, and if you get less than that (a short message, like "This is a message to send"). Then, you try to read more data, but there's none there, so you get a return value of 0, and confuse the server.

  8. #8
    Registered User lantzvillian's Avatar
    Join Date
    Sep 2010
    Posts
    44
    Well the client is consistently sending a packet every 10 seconds to the server - same payload. I want the server to keep checking because I will turn this into a concurrent server after I get this prototype going.

    The ultimate goal is to get X number of connections and count packets sent from clients until it crashes.

    Anduril - removing the loops is fine, I understand the point about the infinite reads and the conn' closing, but the client never closes the connection with this code - the server does right now. What do you propose then?

    CommonTater - I want to prevent standby so I can profile this code vs something that uses epoll.

  9. #9
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    So you want the server to close a connection for a client if it missed a heartbeat from said client? If that's the case, you should probably record the time of the last successful heartbeat for each client/socket and every second or so, check all your clients. If the time difference is more than a certain amount, consider the client dead and close the connection.

  10. #10
    Registered User lantzvillian's Avatar
    Join Date
    Sep 2010
    Posts
    44
    Simply enough, this works and doesn't bother if the client exits.

    Code:
    if (FD_ISSET(sockfd, &rset))
    		  {
    		    bp = buf;
    		    memset(buf,0,sizeof(buf));
    		    bytes_to_read = strlen("This is a message to send\n\r");
    		    
    		    for (;;)
    		    {
    		      n = read(sockfd, bp, bytes_to_read);
    		      if (n == 0)
    		      {
    			//no data or coms is closed
    			break;
    		      }
    		      else if (n == -1)
    		      {
    			printf("Error on read\n");
    			break;
    		      }
    		      else
    		      {
    			bp += n;
    			bytes_to_read -= n;
    		
    			if (bytes_to_read <= 0)
    			{
    			  printf("%s sent: %s", inet_ntoa(client_addr.sin_addr), buf);
    			  memset(buf,0,sizeof(buf));
    			}
    		      }
    		    }
    		    
    		    if (--nready <= 0)
    		      break;        // no more readable descriptors
    		  }
    And now I have to use forking or something to do deal with the concurrency. I'm entirely

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. sending n no of char data uning send() function,
    By thebrighter in forum Windows Programming
    Replies: 1
    Last Post: 08-22-2007, 12:26 PM
  2. send file via socket
    By beon in forum Networking/Device Communication
    Replies: 10
    Last Post: 05-21-2007, 09:12 PM
  3. CString conversion for socket send()
    By WaterNut in forum C++ Programming
    Replies: 13
    Last Post: 04-27-2005, 04:55 PM
  4. LISP (DrScheme) any one?
    By Jeremy G in forum A Brief History of Cprogramming.com
    Replies: 5
    Last Post: 03-31-2004, 12:52 PM
  5. Email attachment via smtp - how?!
    By lucky760 in forum C++ Programming
    Replies: 2
    Last Post: 07-04-2002, 07:59 PM