struct sockaddr与struct sockaddr_in ,struct sockaddr_un的区别和联系_struct sockaddr与struct sockaddr_un-程序员宅基地

技术标签: Socket  

sockaddr

struct sockaddr {
unsigned  short  sa_family;     /* address family, AF_xxx */
char  sa_data[14];                 /* 14 bytes of protocol address */
};


sa_family是地址家族,一般都是“AF_xxx”的形式。好像通常大多用的是都是AF_INET。
sa_data是14字节协议地址。
此数据结构用做bind、connect、recvfrom、sendto等函数的参数,指明地址信息。

但一般编程中并不直接针对此数据结构操作,而是使用另一个与sockaddr等价的数据结构。

sockaddr_in

struct sockaddr是通用的套接字地址,而struct sockaddr_in则是internet环境下套接字的地址形式,二者长度一样,都是16个字节。二者是并列结构,指向sockaddr_in结构的指针也可以指向sockaddr。一般情况下,需要把sockaddr_in结构强制转换成sockaddr结构再传入系统调用函数中。

sockaddr_in(在netinet/in.h中定义):
struct  sockaddr_in {
short  int  sin_family;                      /* Address family */
unsigned  short  int  sin_port;       /* Port number */
struct  in_addr  sin_addr;              /* Internet address */
unsigned  char  sin_zero[8];         /* Same size as struct sockaddr */
};
struct  in_addr {
unsigned  long  s_addr;
};

typedef struct in_addr {
union {
            struct{
                        unsigned char s_b1,
                        s_b2,
                        s_b3,
                        s_b4;
                        } S_un_b;
           struct {
                        unsigned short s_w1,
                        s_w2;
                        } S_un_w;
            unsigned long S_addr;
          } S_un;
} IN_ADDR;

sin_family指代协议族,在socket编程中只能是AF_INET
sin_port存储端口号(使用网络字节顺序)
sin_addr存储IP地址,使用in_addr这个数据结构
sin_zero是为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节。
s_addr按照网络字节顺序存储IP地址

sockaddr_in和sockaddr是并列的结构,指向sockaddr_in的结构体的指针也可以指向
sockadd的结构体,并代替它。也就是说,你可以使用sockaddr_in建立你所需要的信息,
在最后用进行类型转换就可以了。bzero((char*)&mysock,sizeof(mysock));//初始化
mysock结构体名
mysock.sa_family=AF_INET;
mysock.sin_addr.s_addr=inet_addr("192.168.0.1");
……
等到要做转换的时候用:
(struct sockaddr*)mysock

 

通常的用法是:

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); /* short, 网络字节序 */

my_addr.sin_addr.s_addr = inet_addr("192.168.0.1");

bzero(&(my_addr.sin_zero), 8); /* zero the rest of the struct */
//memset(&my_addr.sin_zero, 0, 8);

bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));

#define UNIX_PATH_MAX 108

  struct sockaddr_un {

  sa_family_t sun_family; /*PF_UNIX或AF_UNIX */

  char sun_path[UNIX_PATH_MAX]; /* 路径名 */

  };

几点注意:
1:BSD网络软件中包含了两个函数,用来在二进制地址格式和点分十进制字符串格式之间相互转换,但
是这两个函数仅仅支持IPv4。
       in_addr_t inet_addr(const char *cp);
       char *inet_ntoa(struct in_addr in);
功能相似的两个函数同时支持IPv4和IPv6
       const char *inet_ntop(int domain, const void *addr, char *str, socklen_t size);
       int inet_pton(int domain, const char *str, void *addr);
2:Sockfd是调用socket函数返回的socket描述符,my_addr是一个指向包含有本机IP地址及端口号等信
息的sockaddr类型的指针;addrlen常被设置为sizeof(struct sockaddr)。
  struct sockaddr结构类型是用来保存socket信息的: 
  struct sockaddr { 
   unsigned short sa_family; /* 地址族, AF_xxx */ 
char sa_data[14]; /* 14 字节的协议地址 */ 
}; 
  sa_family一般为AF_INET,代表Internet(TCP/IP)地址族;sa_data则包含该socket的IP地址和端口号。 
  另外还有一种结构类型: 
  struct sockaddr_in { 
   short int sin_family; /* 地址族 */ 
   unsigned short int sin_port; /* 端口号 */ 
   struct in_addr sin_addr; /* IP地址 */ 
   unsigned char sin_zero[8]; /* 填充0 以保持与struct sockaddr同样大小 */ 
  }; 
这个结构更方便使用。sin_zero用来将sockaddr_in结构填充到与struct sockaddr同样的长度,
可以用bzero()或memset()函数将其置为零。指向sockaddr_in 的指针和指向sockaddr的指针可以相
互转换,这意味着如果一个函数所需参数类型是sockaddr时,你可以在函数调用的时候将一个指向 
sockaddr_in的指针转换为指向sockaddr的指针;或者相反。
3:你只要记住,填值的时候使用sockaddr_in结构,而作为函数的 
参数传入的时候转换成sockaddr结构就行了,毕竟都是16个字符 
长。


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 };


sockaddr_un
进程间通信的一种方式是使用UNIX套接字,人们在使用这种方式时往往用的不是网络套接字,而是一种称为本地套接字的方式。这样做可以避免为黑客留下后门。

struct sockaddr_un {

  sa_family_t sun_family; /*PF_UNIX或AF_UNIX */

  char sun_path[UNIX_PATH_MAX]; /* 路径名 */

  };
首先这个结构体是用来本地通信用的,并不是什么tcp/ip通信,虽然代码模式上很相似,准确的说是unix 
Domain 的通信,二者有本质上的区别,那个sun_path成员也就是担任这个domain(域)的角色了,比如存储
“/tmp/mydomain”这样的东西,再比如A和B之间通信,A应该有一个类似"/tmp/A"(名字可以自己随意起)的
域,B应该有一个类似"/tmp/B"的域,通信时分别向对方的域发送消息,从自己的域接受消息。A和B通信时都
是各自初始化对方的域,而创建本身的套接字的时候是初始化自身的 


unix domain的socket通信和网络socket不同的地方在于地址格式不同,用结构体sockaddr_un表示,网络编
程的socket地址是IP地址加端口号,而UNIX Domain Socket的地址是一个socket类型的文件在文件系统中的
路径,这个socket文件由bind()调用创建,如果调用bind()时该文件已存在,则bind()错误返回。

创建
使用套接字函数socket创建,不过传递的参数与网络套接字不同。域参数应该是PF_LOCAL或者PF_UNIX,而不能用PF_INET之类。本地套接字的通讯类型应该是SOCK_STREAM或SOCK_DGRAM,协议为默认协议。例如:
 int sockfd;
 sockfd = socket(PF_LOCAL, SOCK_STREAM, 0);

绑定
创建了套接字后,还必须进行绑定才能使用。不同于网络套接字的绑定,本地套接字的绑定的是struct sockaddr_un结构。struct sockaddr_un结构有两个参数:sun_family、sun_path。sun_family只能是AF_LOCAL或AF_UNIX,而sun_path是本地文件的路径。通常将文件放在/tmp目录下。例如:

 struct sockaddr_un sun;
 sun.sun_family = AF_LOCAL;
 strcpy(sun.sun_path, filepath);
 bind(sockfd, (struct sockaddr*)&sun, sizeof(sun));

监听
本地套接字的监听、接受连接操作与网络套接字类似。

连接
连接到一个正在监听的套接字之前,同样需要填充struct sockaddr_un结构,然后调用connect函数。

连接建立成功后,我们就可以像使用网络套接字一样进行发送和接受操作了。甚至还可以将连接设置为非阻塞模式,这里就不赘述了。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_30736309/article/details/90750898

智能推荐

Python报错ModuleNotFoundError: No module named 'numpy'-程序员宅基地

文章浏览阅读10w+次,点赞108次,收藏197次。Python报错ModuleNotFoundError: No module named ‘numpy’这种情况一般是缺少numpy所致,需要安装numpy。安装numpy的时候需要先更新pip,使用最新版的pip来安装:python -m pip install --upgrade pip然后pip install numpy接下来在命令行窗口运行python然后运行fr..._modulenotfounderror: no module named 'numpy

Python手记-9:Python LXML库XPath的爬取晋江书目_authorid=1322620-程序员宅基地

文章浏览阅读3w次。1. lxml库lxml是功能最丰富且易于使用的库,用于处理Python语言中的XML和HTML,还可实现WEB爬取,官文参考:https://lxml.de/,完整的PDF文档下载链接https://lxml.de/lxmldoc-4.5.0.pdf,但是阅读起来……em……怪自己不够聪明的样子。Linux下安装lxml库:[root@chengyu ~]# pip3 instal..._authorid=1322620

left join查询可能出现重复数据 (主表中一条变两条)_a left join b a有两条数据-程序员宅基地

文章浏览阅读6.7w次,点赞5次,收藏17次。创建两个表 执行下列查询语句SELECT * from person a LEFT JOIN people b on a.action_id = b.action_id显然 person表中的数据出现了两次 ,left join 以主表为主 ,我们在今后的开发要注意类似的问题执行下面的语句也是同样的效果SELECT * from person_a left join b a有两条数据

redis客户端RedisDesktopManager连接常见问题_redis desktop manager 新建连接点击不了ok-程序员宅基地

文章浏览阅读1.9k次。RedisDesktopManager是一款连接redis数据库的客户端。背景:我是在自己机器上装的redis,使用的是虚拟机,系统是linux 版本是centeros-6.4在使用这个连接redis的时候,发现连接不上。第一步:在自己的本机外面试下能不能连接上虚拟机,打开cmd,使用 ping 192.168.232.132 (192.168.232.132这个为虚拟机的ip地址..._redis desktop manager 新建连接点击不了ok

无法安装此app,因为无法验证其完整性 ,解决方案_无法验证完整性的app怎么安装苹果-程序员宅基地

文章浏览阅读3.4k次。(╯□╰)o一群小币崽子没看我资源介绍直接点下载地址一顿操作。证书及描述文件过期 (没有签名或者不完整)_无法验证完整性的app怎么安装苹果

pringMVC-程序员宅基地

文章浏览阅读109次。http://elim.iteye.com/category/175984

随便推点

找到一个数组中只出现一次的数_一个整数数组一个数只出现了1次-程序员宅基地

文章浏览阅读3.2k次,点赞5次,收藏10次。你有没有遇到这样的题,在一个数组中,只有1个数字出现一次,其他的数字都出现了两次,那么你能找到这个只出现一次的数字么?这只是简单的1.0版本,还有如果在这个数组中,有两个数字出现了一次,其他的数字都出现了两次,那么你能找到这两个数字么?还有2.0版本,三个数字出现一次呢?四个呢?五个呢?你要怎么去实现呢?首先,我们一步一步来,从找一个数字开始,其实,如果不是考虑到内存的关系,用桶排序是..._一个整数数组一个数只出现了1次

Java HotSpot(TM) 64-Bit Server VM warning: Sharing is only supported for boot loader classes解决方法-程序员宅基地

文章浏览阅读3.5w次,点赞33次,收藏41次。在我尝试用IDEA进行调试时,IDAE报错:Java HotSpot 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended翻译过来就是:Java HotSpot(TM)64位服务器虚拟机警告:共享仅支持引导加载程序类,因为已附加引导程序类路径解决方案:打开设置,在搜索框内输入:async,然后去掉以下勾选即_java hotspot(tm) 64-bit server vm warning: sharing is only supported for boo

新型高强度铝合金焊条_变形铝合金焊条-程序员宅基地

文章浏览阅读404次。1.2mm)的Al-12.7Si-0.7Mg成分铝合金焊丝,自制焊丝表面质量良好,内部组织与成分均匀。这种铝合金焊条的焊芯由铝合金组成,它的成分质量分数如下SC钪0.05%~0.8%,Er铒0.05%~0.6%,硼铬稀土0.01%~0.8%,B硼0.01%~0.5%,Ti钛0.1%~0.3%,Cr铬0.05%~0.4%,Zr锆0.05%.:铁0.15%,硅0.12%,铜0.1%,锰0.02%,镁4.5% ,锌5.5%,TiC碳化钛0.05%,TiB硼化钛0.05%,石墨0.22%其余为6061铝合金。_变形铝合金焊条

python输出二进制数_Python: 二进制、八进制、十六进制转换或者输出-程序员宅基地

文章浏览阅读4.6k次,点赞6次,收藏21次。为了将整数转换为二进制、八进制或十六进制的文本串,可以分别使用bin() ,oct() 或hex() 函数:>>> x = 1234>>> bin(x)'0b10011010010'>>> oct(x)'0o2322'>>> hex(x)'0x4d2'如果你不想输出0b , 0o 或者0x 的前缀的话,可以使用format() 函数>>> format(x, 'b')'10011010010'>>..._python怎么输出a的二进制,八进制,十六进制

python爬取网页乱码解决方案_python爬取网页特殊字符乱码怎么解决-程序员宅基地

文章浏览阅读199次。importchardetimportrequestsurl='http://www.100253.com/'d1=requests.get(url)codesty=chardet.detect(d1.content)a=d1.content.decode(codesty['encoding'])a.encode('utf-8')_python爬取网页特殊字符乱码怎么解决

单片机 MSP430 G2553 launchpad LCD1602 显示 连线_msp430怎么连线-程序员宅基地

文章浏览阅读2.2k次。一般无特殊计划 买的LCD1602显示屏是5V版本的,不是3.3特殊版本,这时候怎么连线。下图画正方形的2个孔,上面是5V,下面是板子的GND。下图右上角的VCC是3.3V.接线方式:成功:_msp430怎么连线

推荐文章

热门文章

相关标签