Link to home
Start Free TrialLog in
Avatar of comphil
comphilFlag for United Kingdom of Great Britain and Northern Ireland

asked on

C Sockets - Split message into packets?

We are attempting to create a pair of programs (client & server) - one of which will send a message (server) and one of which will recieve (client).  This works, with the user providing the ip of the client and a message to send.

However, we would like to break the message down into packets so that we can send longer messages.  We have searched everywhere and cannot find any hints or tutorials on how to achieve this.

Basically we would like to know, given that the message (for example) is stored in a variable called "message", how would one break "message" down into individual packets?  We have got as far as creating a struct called "packet" with variables for buffer[256], sequence_no and flag, but are unsure how to continue and how to use this to break down the message.

Any assistance gratefully recieved,

Phil
ASKER CERTIFIED SOLUTION
Avatar of PaulCaswell
PaulCaswell
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of comphil

ASKER

Many thanks for your help, will try this in a second!

One more question for the moment: any suggestions on how to get the reciever to decode the sequence?  Sorry to sound cheeky but don't really know how to go about that properly at the moment!

Many thanks

Phil
Avatar of grg99
grg99

Are you using UDP or TCP?

If it's UDP, it's a difficult thing to do, better use TCP.

With a TCP connection you can use any standard I/O function to write to the socket, just as if it was a file, on the receiving end you can use read(), just like with a file.   TCP does all the buffering, packetizing, and sequencing for you.



Avatar of comphil

ASKER

Sorry, should have said, we are using UDP - aware that TCP is better but we need to use UDP in this case, which is why it is such a headache.

Phil
Phil,

At the other end receive the packets as normal, reorder them into sequence as specified by the sequence number and use each one's length to decide where to put its data.

Something like this but with much more checking and you need to handle the case where a packet gets lost:

void ReceiveMessage ( char * message, int maxLen )
{
 struct Packet packet;
 while (ReceivePacket(&packet))
 {
  int position = packet.sequence * sizeof(packet.data);
  memcpy ( &message[position], packet.data, message.length );
 }
}

Paul
it's really hard to make UDP act like TCP.   it took years of work to get TCp to work well and handle unusual situations, like duplicated packets, delayed packets, packets out of sequence, net congestion, optimal buffering and retries, minimal acks, and quite a few other cases.

Do you need absolute data integrity and reliability, even on flaky amnd/or congested networks?  If so, expect to spend a year at least getting UDP to do this.

Greg's right. To do this reliably you need a mature multipath protocol. My code just demonstrates one of the simplest methods of splitting, transmitting and reassembling a message. There are many more.

Paul
Avatar of comphil

ASKER

Thanks for your help so far, I am aware that TCP is far better for this but we are required to use UDP for some reason at the moment.

I have inserted the code you provided originally and modified to suit my needs.  However, so far I have not been able to compile it.  I have cleared most errors but now am getting the following:

/tmp/ccCdaefe.o(.text+0x97): undefined reference to 'SendPacket'
/tmp/ccCdaefe.o(.text+0xe7): undefined reference to 'SendPacket'

I have found nothing on the internet to help with this and cannot see what is wrong with it.  The functio n "sendMessage" has not been changed from what you provided except for declaring true + false as int variables.

I don't honestly know what it is complaining about now - can you see the problem?

Many thanks

Phil
This code was intended as an example. The SendPacket function must be written by you and must send the packet structure through whatever protocol you wish. It should look something like:

void SendPacket ( struct Packet * packet )
{
 UDPSend ( packet, sizeof(*packet) - sizeof(packet->data) + packet->length);
}

Paul
Avatar of comphil

ASKER

Ah, I see now, I was misreading the code.  I do have that function but it's named differently!  Thanks again.

Phil
Avatar of comphil

ASKER

Ok,

We've tried and tried and tried to get this thing to work.  So far no luck.  To be quite frankly honest we aren't entirely sure what we're doing, if you hadn't already noticed.  

We have searched the internet high and low, probably looked at 50+ different sites and nothing even comes close to showing how this is done.  I feel bad asking for any more help with this as you've given so many hints so far, but we have tried to modify your examples to work with our needs and it still doesn't compile or work - each time it fails to compile we'll go in and change something around and remove that error, only for more to crop up and now we've hit a point where we're completely stuck.

We are aware that doing this with UDP is stupid and TCP is far better, but UDP has been required so that's what we have to use.  

If there is anything else you can show us to make this clearer, much appreciated, if not thanks anyway and points for the help given will be distributed.

Many thanks

Phil
Post your code! Probably the code that compiles but that's not a problem.

Paul
Avatar of comphil

ASKER

OK, wasn't going to unless you asked because it's quite long.  Here's the server:

/*server*/

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/wait.h>

#define MYPORT 4950

struct packet
{
      int seq_no;
      char flag;
      char buffer[256];
}mypacket;

char temp_buffer[256];
int i;

int main(int argc, char *argv[])
{
      int sockfd;
      struct sockaddr_in their_addr;
      struct hostent *he;
      int numbytes;
      mypacket mp;

      if (argc != 3)
      {
            fprintf(stderr,"usage: talker hostname message\n");
            exit(1);
      }

      if ((he=gethostbyname(argv[1])) == NULL)
      {
            herror("gethostbyname");
            exit(1);
      }

      if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
      {
            perror("socket");
            exit(1);
      }

      their_addr.sin_family = AF_INET;
      their_addr.sin_port = htons(MYPORT);

      their_addr.sin_addr = *((struct in_addr *)he->h_addr);

      bzero(&(their_addr.sin_zero), 8);

      mp.seq_no = 1;
      mp.flag = 0;

      if ((numbytes=sendto(sockfd, argv[2], strlen(argv[2]), 0, &mypacket, sizeof(mypacket),(struct sockaddr *)&their_addr, sizeof(struct sockaddr))) == -1)
      {
            perror("sendto");
            exit(1);
      }

      printf("Sent %d bytes to %s\n",numbytes,inet_ntoa(their_addr));

      close(sockfd);
      return 0;
}

We're aware that this isn't going to work with packets, although it compiles and works OK - this is as far as we got with a compiling and working program - basically we're trying to convert this program to work with packets.

And here's the client:

/*client*/

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>

#define MYPORT 4950

#define MAXBUFLEN 100

struct packet
{
      int seq_no;
      char flag;
      char buffer[250];      
}mypacket;

main()
{
      int sockfd;
      struct sockaddr_in my_addr;
      struct sockaddr_in their_addr;
      int addr_len, numbytes;
      char buf[MAXBUFLEN];
      mypacket mp;      
      int tempseq_no;      
      
      tempseq_no = 0;

      if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
      {
            perror("socket");
            exit(1);
      }

      my_addr.sin_family = AF_INET;
      my_addr.sin_port = htons(MYPORT);
      
      my_addr.sin_addr.s_addr = INADDR_ANY;
      bzero(&(my_addr.sin_zero), 8);
      
      if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1)
      {
            perror("bind");
            exit(1);
      }
      
      while(1)
      {
      addr_len = sizeof(struct sockaddr);
      if ((numbytes=recvfrom(sockfd, buf, MAXBUFLEN, 0, (struct sockaddr *)&their_addr,             &addr_len)) == -1)
      {
            perror("recvfrom");
            exit(1);
      }
      
      if (mypacket.seq_no < tempseq_no)
      {
      printf("Got packet from %s\n",inet_ntoa(their_addr.sin_addr));
      printf("Packet is %d bytes long\n",numbytes);

      buf[numbytes] = '\0';
      printf("Packet contains \"%s\"\n",buf);
      }
      else tempseq_no = mypacket.seq_no

      if (tempseq_no < mypacket.seq_no)
      {
      printf("ERROR: The sequence number of the recieved packet is too small")
      }
      
      close(sockfd);
}

Again, this compiles and works but we know it isn't going to work with packets yet as it's not complete - just as far as we've got.

Hope this makes our problem a bit clearer!

Many thanks

Phil
Avatar of comphil

ASKER

We may have a solution to this problem now, thanks for your help.  Points have been given.

Phil