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


1. sockaddr_in , sockaddr , in_addr区别

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

1.1 sockaddr:通用的socket地址

struct sockaddr {
    unsigned   short   sa_family;     
    char   sa_data[14];     
};  

1.2 sockaddr_in:Internet socket

sockaddr和sockaddr_in可以进行类型转换

struct sockaddr_in {  
    short   int   sin_family;     
    unsigned   short   int   sin_port;     
    struct   in_addr   sin_addr;     
    unsigned   char   sin_zero[8];     
};

1.3 in_addr:32位IP地址。

struct   in_addr   {  
    union {
        struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
        struct { u_short s_w1,s_w2; } S_un_w;
        u_long S_addr; 
    } S_un;
    #define s_addr  S_un.S_addr
};

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

1.4 用法

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

通常的用法是:

int   sockfd;  
struct   sockaddr_in   my_addr;  
sockfd   =   socket(AF_INET,   SOCK_STREAM,   0);     
   
my_addr.sin_family   =   AF_INET;     
my_addr.sin_port   =   htons(MYPORT);     
my_addr.sin_addr.s_addr   =   inet_addr("192.168.0.1");  
   
bzero(&(my_addr.sin_zero),   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.名词解析:

  • 主机字节序:
    不同的CPU有不同的字节序类型,这些字节序是指整数在内存中保存的顺序,这个叫做主机序。最常见的有两种 1.Little endian:低字节存高地址,高字节存低地址 2.Big endian:低字节存低地址,高字节存高地址
  • 网络字节序:
    网络字节顺序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节顺序采用big endian排序方式。
  • 字节序转换
    为了进行转换bsd socket提供了转换的函数,有下面四个网络与主机字节转换函数:htons ntohs htonl ntohl
    s==>short
    l==>long
    h==>host
    n==>network
  • 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数据结构:

struct hostent { 
   char *h_name; 
   char **h_aliases; 
   int h_addrtype; 
   int h_length; 
   char **h_addr_list; 
}; 
#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()。)

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

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

注意
在使用 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

  • 相关函数
    send , sendmsg,recv , recvfrom , socket
  • 表头文件
    #include < sys/types.h >
    #include < sys/socket.h >
  • 定义函数
int sendto ( socket s , const void * msg, int len, unsigned int flags, const struct sockaddr * to , int tolen ) ;
  • 函数说明
    sendto() 用来将数据由指定的socket传给对方主机。
  • 参数们:
    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 传给系统调用的参数不正确。
  • 范例
#include < sys/types.h >
#include < sys/socket.h >
#include 
#define PORT 2345 /*使用的port*/
main(){
  int sockfd,len;
  struct sockaddr_in addr;
  char buffer[256];
  /*建立socket*/
  if(sockfd=socket (AF_INET,SOCK_DGRAM,0))<0){
      perror (“socket”);
      exit(1);
  }
  /*填写sockaddr_in 结构*/
  bzero ( &addr, sizeof(addr) );
  addr.sin_family=AF_INET;
  addr.sin_port=htons(PORT);
  addr.sin_addr=hton1(INADDR_ANY) ;
  if (bind(sockfd, &addr, sizeof(addr))<0){
      perror(“connect”);
      exit(1);
  }
  while(1){
      bzero(buffer,sizeof(buffer));
      len = recvfrom(socket,buffer,sizeof(buffer), 0 , &addr &addr_len);
      /*显示client端的网络地址*/
      printf(“receive from %s\n “ , inet_ntoa( addr.sin_addr));
      /*将字串返回给client端*/
      sendto(sockfd,buffer,len,0,&addr,addr_len);
  }
}

执行 请参考recvfrom()

你可能感兴趣的:(读pdcp_lte_logger.c代码学会的新知识)