[关闭]
@natsumi 2015-02-20T17:30:52.000000Z 字数 4144 阅读 1207

读pdcp_lte_logger.c代码学会的新知识

LTE Wireshark pdcp


1. sockaddr_in , sockaddr , in_addr区别

整理自http://blog.csdn.net/jackychu/article/details/4461927
另一篇相关文章以备参考:struct sockaddr与struct sockaddr_in的区别和联系

1.1 sockaddr:通用的socket地址

  1. struct sockaddr {
  2. unsigned short sa_family;
  3. char sa_data[14];
  4. };

1.2 sockaddr_in:Internet socket

sockaddr和sockaddr_in可以进行类型转换

  1. struct sockaddr_in {
  2. short int sin_family;
  3. unsigned short int sin_port;
  4. struct in_addr sin_addr;
  5. unsigned char sin_zero[8];
  6. };

1.3 in_addr:32位IP地址。

  1. struct in_addr {
  2. union {
  3. struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
  4. struct { u_short s_w1,s_w2; } S_un_w;
  5. u_long S_addr;
  6. } S_un;
  7. #define s_addr S_un.S_addr
  8. };

inet_addr()是将一个点分制的IP地址(如192.168.0.1)转换为上述结构中需要的32位IP地址(0xC0A80001)。

1.4 用法

填值的时候使用sockaddr_in结构,而作为函数(如socket, listen, bind等)的参数传入的时候转换成sockaddr结构就行了,毕竟都是16个字符长。

通常的用法是:

  1. int sockfd;
  2. struct sockaddr_in my_addr;
  3. sockfd = socket(AF_INET, SOCK_STREAM, 0);
  4. my_addr.sin_family = AF_INET;
  5. my_addr.sin_port = htons(MYPORT);
  6. my_addr.sin_addr.s_addr = inet_addr("192.168.0.1");
  7. bzero(&(my_addr.sin_zero), 8);
  8. bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));

可以用C++做个不太准确的假设。
sockaddr是base class
sockaddr_in等是derived(派生) class
如此一来,bind, connect, sendto, recvfrom等函数就可以使用base class
来处理多种不同的derived class了。
但是实际上,这是没有继承关系数据结构(C嘛),所以需要强制造型来转换数据类型。正因为如此,在sendto的时候需要给出len长度,因为不同的sockaddr_xx实现长度并不相同。

1.5 P.S.名词解析:

  • htons:把unsigned short类型从主机序转换到网络序
  • htonl:把unsigned long类型从主机序转换到网络序
  • ntohs:把unsigned short类型从网络序转换到主机序
  • ntohl:把unsigned long类型从网络序转换到主机序

在使用little endian的系统中 这些函数会把字节序进行转换
在使用big endian类型的系统中这些函数会定义成空宏

2. gethostbyname()的返回值类型struct hostent

整理自http://blog.csdn.net/wangjie5540/article/details/23429083

2.1 hostent数据结构:

  1. struct hostent {
  2.   char *h_name;
  3.   char **h_aliases;
  4.   int h_addrtype;
  5.   int h_length;
  6.   char **h_addr_list;
  7. };
  8. #define h_addr h_addr_list[0]

这个数据结构的详细资料:
struct hostent:

  • h_name – 地址的正式名称。
  • h_aliases – 空字节-地址的预备名称的指针。
  • h_addrtype –地址类型; 通常是AF_INET。
  • h_length – 地址的比特长度。
  • h_addr_list – 零字节-主机网络地址指针。网络字节顺序。
  • h_addr - h_addr_list中的第一地址。

2.2 gethostbyname()的使用

相当简单,你只是传递一个保存机器名的字符串(例如 "whitehouse.gov") 给gethostbyname(),然后从返回的数据结构struct hostent中获取信息。

gethostbyname()成功时返回一个指向结构体hostent的指针,或者是个空(NULL) 指针。(但是和以前不同,不设置errno,h_errno设置错 误信息。请看下面的 herror()。)

如何使用呢? 这个函数可不象它看上去那么难用。
这里是个例子:

  1. int main(int argc, char *argv[]) {
  2. struct hostent *h;
  3. if (argc != 2) { /* 检查命令行 */
  4. fprintf(stderr,"usage: getip address ");
  5. exit(1);
  6. }
  7. if ((h=gethostbyname(argv[1])) == NULL) { /* 取得地址信息 */
  8. herror("gethostbyname");
  9. exit(1);
  10. }
  11. printf("Host name : %s ", h->h_name);
  12.   printf("IP Address : %s ",inet_ntoa(*((struct in_addr *)h->h_addr)));
  13. return 0;
  14. }

注意
在使用 gethostbyname() 的时候,你不能用perror() 打印错误信息 (因为 errno 没有使用),你应该调用 herror()。

唯一也许让人不解的是输出 IP 地址信息。h->h_addr 是一个 char *, 但是 inet_ntoa() 需要的是 struct in_addr。因此,我转换 h->h_addr 成 struct in_addr *,然后得到数据。

3. sendto():经socket传送数据

整理自http://blog.csdn.net/tdk_root/article/details/7888574

  1. int sendto ( socket s , const void * msg, int len, unsigned int flags, const struct sockaddr * to , int tolen ) ;
  • 参数们:
    s:已建好连线的socket,如果利用UDP协议则不需经过连线操作
    msg:指向欲连线的数据内容
    flags 一般设0,详细描述请参考send()。
    to:用来指定欲传送的网络地址,结构sockaddr请参考bind()。
    tolen:sockaddr的结构长度。
  • 返回值:
    成功则返回实际传送出去的字符数,失败返回-1,错误原因存于errno 中。
  • 错误代码
      EBADF 参数s非法的socket处理代码。
      EFAULT 参数中有一指针指向无法存取的内存空间。
      WNOTSOCK 参数 s为一文件描述词,非socket。
      EINTR 被信号所中断。
      EAGAIN 此动作会令进程阻断,但参数s的socket为不可阻断的。
      ENOBUFS 系统的缓冲内存不足。
      EINVAL 传给系统调用的参数不正确。
  1. #include < sys/types.h >
  2. #include < sys/socket.h >
  3. #include <arpa.inet.h>
  4. #define PORT 2345 /*使用的port*/
  5. main(){
  6.   int sockfd,len;
  7.   struct sockaddr_in addr;
  8.   char buffer[256];
  9.   /*建立socket*/
  10.   if(sockfd=socket (AF_INET,SOCK_DGRAM,0))<0){
  11.    perror (“socket”);
  12.    exit(1);
  13.   }
  14.   /*填写sockaddr_in 结构*/
  15.   bzero ( &addr, sizeof(addr) );
  16.   addr.sin_family=AF_INET;
  17.   addr.sin_port=htons(PORT);
  18.   addr.sin_addr=hton1(INADDR_ANY) ;
  19.   if (bind(sockfd, &addr, sizeof(addr))<0){
  20.    perror(“connect”);
  21.    exit(1);
  22.   }
  23.   while(1){
  24.    bzero(buffer,sizeof(buffer));
  25.    len = recvfrom(socket,buffer,sizeof(buffer), 0 , &addr &addr_len);
  26.    /*显示client端的网络地址*/
  27.    printf(“receive from %s\n , inet_ntoa( addr.sin_addr));
  28.    /*将字串返回给client端*/
  29.    sendto(sockfd,buffer,len,0,&addr,addr_len);
  30.   }
  31. }

执行 请参考recvfrom()

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注