将htonl()和ntonhl()用于unsigned char

时间:2011-07-29 02:00:14

标签: c sockets

我正在粘贴下面的客户端和服务器代码。我的程序运行正常,除了我试图在我的src和dest字段中发送一个ipaddress,由于某种原因,即使我发送它为131.199.166.232,它打印为232.166.199.131。但我的其余数据包值以适当的方式打印。我已经使用了memcpy(),所以我觉得它是一个memcpy的东西,在某个地方我做错了,但在Beej的指南中,因为有一个部分@在不同的计算机体系结构中的字节排序.....我没有使用过htonl()所有,也许是因为那个。请指导我,因为我出错了。另外请告诉我发送数据的方式,如何在我的代码中使用htonl()函数....提前感谢。

客户:

       #include <stdio.h>
     #include <stdlib.h>
     #include <string.h>
     #include <math.h>
     #include <sys/types.h>
     #include <sys/socket.h>
     #include <netinet/in.h>
     #include <netdb.h>
     #define MAXPROFILES  2

    int main(int argc, char *argv[])

  {
    int sockfd, portno, n;
    struct sockaddr_in serv_addr;
    struct hostent *server;
    unsigned char buf[1024];
    unsigned int srcAddress = 2193598184;
    unsigned int destAddress = 2193598182;

   struct profile_t
 {
   unsigned char length;
   unsigned char type;
   unsigned char *data;
 };

   typedef struct profile_datagram_t
 {
unsigned char src[4];
unsigned char dst[4];
unsigned char ver;
unsigned char n;
struct profile_t profiles[MAXPROFILES];
 } header;


    header outObj;

    int j =0;
    int i =0;
   // for loop for doing the malloc so that we can allocate memory to all profiles
    for(i=0;i<MAXPROFILES;i++){
outObj.profiles[i].data = malloc(5);
  }


    for(i=3;i>=0;i--){
outObj.src[i] = (srcAddress >> (i*8)) & 0xFF;
outObj.dst[i] = (destAddress >> (i*8)) & 0xFF;
printf("%d",outObj.src[i]);
 }
    outObj.ver = 1;
    outObj.n = 2;

    memcpy(buf,&outObj.src,4);
    memcpy(buf+4,&outObj.dst,4);
    memcpy(buf+8,&outObj.ver,1);
    memcpy(buf+9,&outObj.n,1);


    outObj.profiles[0].length = 5;
    outObj.profiles[0].type = 1;
    outObj.profiles[1].length = 5;
    outObj.profiles[1].type = 2;

    for(i=0;i<MAXPROFILES;i++){
for(j=0;j<5;j++){
    outObj.profiles[i].data[j] = j+1;
}

}

    int k = 10;

        // for loop to do memcopy of length,type and data.
    for(i=0;i<MAXPROFILES;i++){
memcpy(buf+k,&outObj.profiles[0].length,1);
memcpy(buf+k+1,&outObj.profiles[0].type,1);
memcpy(buf+k+2,outObj.profiles[0].data,5);
k +=7;

}

   if (argc < 3) {
   fprintf(stderr,"usage: %s hostname port\n", argv[0]);
   exit(0);
}
   portno = atoi(argv[2]); //Convert ASCII to integer
   sockfd = socket(AF_INET, SOCK_STREAM, 0); // socket file descriptor


   if (sockfd < 0)
   error("ERROR DETECTED !!! Problem in opening socket\n");

   server = gethostbyname(argv[1]);
   if (server == NULL) {
   fprintf(stderr,"ERROR DETECTED !!!, no such server found \n");
    exit(0);
}

  bzero((char *) &serv_addr, sizeof(serv_addr)); //clear the memory for server address

  serv_addr.sin_family = AF_INET;
  bcopy((char *)server->h_addr,
        (char *)&serv_addr.sin_addr.s_addr,
     server->h_length);

  serv_addr.sin_port = htons(portno);

  printf("Client 1 trying to connect with server host %s on port %d\n", argv[1], portno);


  if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
  error("ERROR in connection");

      printf("SUCCESS !!! Connection established \n");


   if (write(sockfd, buf, k) < 0)
   {
  error("Write error has occured ");
   }


  return 0;

服务器:

          #include <stdio.h>
           #include <stdlib.h>
           #include <string.h>
           #include <sys/types.h>
           #include <sys/socket.h>
           #include <netinet/in.h>
           #define MAXPROFILES  2

           int main(int argc, char *argv[])
        {
           int sockfd, newsockfd, portno, clilen;
           struct sockaddr_in serv_addr, cli_addr;
           unsigned char buf[1024];
           int my_data2[10] = {1,3,9,10};
           int my_data[10] = {1,2,3,4,5};
       int myDataBinary[500] = {0};
       int myDataBinary2[500] = {0};
       int recData[500] = {0};
       int index1=0;


       struct profile_t
        {
        unsigned char length;
        unsigned char type;
        unsigned char *data;
        };

            typedef struct profile_datagram_t
       {
        unsigned char src[4];
        unsigned char dst[4];
        unsigned char ver;
        unsigned char n;
       struct profile_t profiles[MAXPROFILES];
        } header;


            header outObj;

        int j =0;
        int i =0;



            if (argc < 2) {
            fprintf(stderr,"usage: %s port_number1",argv[0]);
            exit(1);
         }
            sockfd = socket(AF_INET, SOCK_STREAM, 0);
            if (sockfd < 0)
            error("ERROR DETECTED !!! Problem in opening socket");

            bzero((char *) &serv_addr, sizeof(serv_addr));
            portno = atoi(argv[1]);

            serv_addr.sin_family = AF_INET;
            serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
            serv_addr.sin_port = htons(portno);

            if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
            error("ERROR DETECTED !!! There was a problem in binding");

            listen(sockfd, 10);
            clilen = sizeof(cli_addr);



             printf("Server listening on port number %d...\n", serv_addr.sin_port);

             newsockfd = accept(sockfd,(struct sockaddr *) &cli_addr, &clilen);

             if (newsockfd < 0)
         error("ERROR DETECTED !!! the connection request was not accepted");

         int rc = read(newsockfd,buf,100);
         if(rc < 0){
     printf("error");
      }
         else {
        printf("success %d",rc);
      }


      memcpy(&outObj.src,buf+0,4);
      memcpy(&outObj.dst,buf+4,4);
      memcpy(&outObj.ver,buf+8,1);
      memcpy(&outObj.n,buf+9,1);

          printf("\nsrc ip = ");
          for(int i=0;i<4;i++){
       printf("%d ",outObj.src[i]);
       }

          printf("\ndest ip = ");
          for(int i=0;i<4;i++){
         printf("%d ",outObj.src[i]);
        }

         printf("\nversion = %d",outObj.ver);
         printf("\nnumber = %d",outObj.n);

         int k = 10;

         for(i=0;i<outObj.n;i++){
     memcpy(&outObj.profiles[i].length,buf+k,1);
     memcpy(&outObj.profiles[i].type,buf+k+1,1);
     outObj.profiles[i].data = malloc(outObj.profiles[i].length);
     memcpy(outObj.profiles[i].data,buf+k+2,5);
        k +=7;
       }

         for(int i=0;i<outObj.n;i++){
    printf("\nMessage %d :",i+1);
    printf("\nLength : %d",outObj.profiles[i].length);
    printf("\nType : %d",outObj.profiles[i].type);
    for(int j=0;j<5;j++){
        printf("\ndata %d : %d",j,outObj.profiles[i].data[j]);
    }
}


         for(int i=0; i<sizeof(my_data)/sizeof(int);i++)
      {
     if(my_data[i] > 0){
    index1 = my_data[i];
    myDataBinary[index1] = 1;
    printf("my data %d = %d\n",index1,myDataBinary[index1]);
}
}

       for(int i=0; i<sizeof(my_data2)/sizeof(int);i++)
{
    if(my_data2[i] > 0){
        index1 = my_data2[i];
        myDataBinary2[index1] = 1;
        printf("my data %d = %d\n",index1,myDataBinary2[index1]);
    }
}


         int sumRecievedData = 0;
         int sumMyData = 0;
         int sumMultpliedData = 0;
         float Cov =0;
         float sdMyData = 0;
         float sdRecievedData =0;
         int n = 500;
         float rho;

                for(int i=0;i<outObj.n;i++){
              index1=0;
              for (int j=0; j<outObj.profiles[i].length;j++) {

               if(outObj.profiles[i].data[j] > 0){
               index1 = outObj.profiles[i].data[j];
               recData[index1] = 1;
              printf("rec data %d = %d\n",index1,recData[index1]);
       }
     }
   }


        return 0;

    }

2 个答案:

答案 0 :(得分:1)

ip地址实际上只是unsigned char的数组。

uchar ip[] = {127,0,0,1};

是环回地址的精确表示。但是一个包含四个字节的数组,而int实际上并不是那么大;有一个例外 endiannes !所以假设我创建了代表该ip的int。一种天真的方法可能是:

 int ip = (127<<24)|(0<<16)|(0<<8)|(1)

当然,在 little endian 计算机上,就像x86和arm一样:

char *char_ip = (void*)&ip;

并迭代该aray将产生:

1, 0, 0, 127

但是在 big endian 计算机上,如PowerPC或SPARC,我们会得到我们期望的结果,

127, 0, 0, 1

Big endian也被称为“网络字节顺序”,这是htonl中的n代表:“host to network long”。通过网络读取或写入整数时经常使用这些函数。假设服务器想要向客户端发送一些号码:

uint32_t important = htonl(42);
write(client, &important, sizeof important);

然后,要阅读它,客户端会:

uint32_t important;
read(server, &important, sizeof important);
important = ntohl(important);

您的IP地址被翻转的原因是因为IP地址预计将按网络字节顺序排列,但您的IP地址则为小端。 htonl上的int - 类型的ip会为你翻转它。

答案 1 :(得分:0)

这对我来说太多代码了,但是如果你只是想创建一个字节数组来进行序列化,你根本不需要任何特殊的函数,你可以用代数编写它:

unsigned char buf[sizeof(uint_type)];

uint_type value;

for (size_t i = 0; i != sizeof(uint_type); ++i)
{
  // Little-endian
  buf[i] = value >> (i * CHAR_BIT);

  // Big-endian
  buf[sizeof(uint_type - i - 1)] = value >> (i * CHAR_BIT);
}

请注意,此代码与系统的字节顺序无关。


自从你问到,htonl / ntohl函数是直接处理uint32_t整数,没有显式字符数组:

uint32_t value;

myfile.read((char*)&value, sizeof(value));  // network endianness
value = ntohl(value);                       // host endianness

/* fiddle fiddle */

value = htonl(value);
yourfile.write((const char*)&value, sizeof(value));

(我想,更常见的是你要写一个套接字而不是一个文件。)