sockaddr与sockaddr_in

本文主要探讨Linux操作系统中,涉及网络编程的sockaddr结构体及其子类型sockaddr_in的使用。介绍了如何初始化sockaddr_in以及在服务端和客户端的应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在linux下有下面结构:

sockaddr

struct sockaddr 
{
   sa_family_t sa_family;    /*addressfamily,AF_xxx*/
   char        sa_data[14];	 /*variable-length address,14 bytes of protocol address*/
}


sa_family是地址家族,一般都是“AF_xxx”的形式。通常大多用的是都是AF_INET,代表TCP/IP协议族。
sa_data是14字节协议地址。
此数据结构用做bind、connect、recvfrom、sendto等函数的参数,指明地址信息。但一般编程中并不直接针对此数据结构操作,而是使用另一个与sockaddr等价的数据结构.

sockaddr_in(在netinet/in.h中定义)

struct sockaddr_in
{
	sa_family_t sin_family;
		/*Address family,一般来说AF_INET(地址族)PF_INET(协议族)*/
	in_port_t sin_port;
		/*Port number(必须要采用网络数据格式,普通数字可以用htons()函数转换成网络数据格式的数字)*/
	struct in_addr sin_addr;
		/*IPv4 address*/
	unsigned char sin_zero[8];
		/*没有实际意义,只是为了跟sockaddr结构在内存中对齐*/
};

in_addr结构, (在<arpa/inet.h>中定义)

typedef struct in_addr 
{
	in_addr_t s_addr; 
};

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


结构体in_addr 用来表示一个32位的IPv4地址.in_addr_t 一般为 32位的unsigned int,其字节顺序为网络顺序(network byte ordered),即该无符号整数采用大端字节序,其中每8位代表一个IP地址位中的一个数值.例如192.168.3.144记为0xc0a80390,其中 c0 为192 ,a8 为 168, 03 为 3 , 90 为 144打印的时候可以调用inet_ntoa()函数将其转换为char *类型.


sin_family指代协议族,在socket编程中只能是AF_INET
sin_port存储端口号(使用网络字节顺序),在linux下,端口号的范围0~65535,同时0~1024范围的端口号已经被系统使用或保留。
sin_addr存储IP地址,使用in_addr这个数据结构
sin_zero是为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节。可以用bzero()或memset()函数将其置为零。
s_addr按照网络字节顺序存储IP地址。
使用时,先用sockaddr_in建立所需要的信息,然后用memset函数初始化就可以了


sockaddr_in的初始化

sockaddr_in mysock;
memset((char*)&mysock,0,sizeof(mysock));
mysock.sin_family=AF_INET;
mysock.sin_port=htons(1234);//1234是端口号
mysock.sin_addr.s_addr=inet_addr("192.168.0.1");


经典案例

服务端


#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h> //inet_addr();
#include <arpa/inet.h>
#include <errno.h>


extern int errno;


int main()
{
<span style="white-space:pre">	</span>int fd = socket(AF_INET, SOCK_STREAM, 0);
<span style="white-space:pre">	</span>printf("socket id = %d\n", fd);


<span style="white-space:pre">	</span>struct sockaddr_in servaddr;


<span style="white-space:pre">	</span>servaddr.sin_family = AF_INET;
<span style="white-space:pre">	</span>servaddr.sin_port = htons(11111);
<span style="white-space:pre">	</span>servaddr.sin_addr.s_addr = htonl(INADDR_ANY);


<span style="white-space:pre">	</span>int ret = bind(fd, (struct sockaddr*)&servaddr, sizeof(servaddr));
<span style="white-space:pre">	</span>if(ret < 0)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>fprintf(stderr, "error:%d\n", strerror(errno));
<span style="white-space:pre">		</span>close(fd);
<span style="white-space:pre">		</span>return -1;
<span style="white-space:pre">	</span>}


<span style="white-space:pre">	</span>listen(fd, 5);
<span style="white-space:pre">	</span>struct sockaddr_in peer; //保存对方的地址信息
<span style="white-space:pre">	</span>socklen_t size;
<span style="white-space:pre">	</span>size = sizeof(peer);
<span style="white-space:pre">	</span>int newfd = accept(fd, (struct sockaddr*)&peer, &size);


<span style="white-space:pre">	</span>printf("ip: %s, port: %d\n", inet_ntoa(peer.sin_addr), ntohs(peer.sin_port));


<span style="white-space:pre">	</span>char buff[100];
<span style="white-space:pre">	</span>//fgets(buff, 100. stdin);
<span style="white-space:pre">	</span>//write(newfd, buff, strlen(buff));
<span style="white-space:pre">	</span>int cnt = read(newfd, buff, 100);
<span style="white-space:pre">	</span>write(STDOUT_FILENO, buff, cnt);
<span style="white-space:pre">	</span>close(newfd);
<span style="white-space:pre">	</span>return 0;
}


客户端


#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h> //inet_addr();
#include <arpa/inet.h>
#include <errno.h>


extern int errno;


int main()
{
<span style="white-space:pre">	</span>int fd = socket(AF_INET, SOCK_STREAM, 0);
<span style="white-space:pre">	</span>printf("socket id = %d\n", fd);


<span style="white-space:pre">	</span>struct sockaddr_in servaddr;
<span style="white-space:pre">	</span>servaddr.sin_family = AF_INET;
<span style="white-space:pre">	</span>servaddr.sin_port = htons(11111);
<span style="white-space:pre">	</span>servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");


<span style="white-space:pre">	</span>connect(fd, (struct sockaddr *)&servaddr, sizeof(servaddr));
<span style="white-space:pre">	</span>int buff[100];
<span style="white-space:pre">	</span>fgets(buff, 100, stdin);
<span style="white-space:pre">	</span>write(fd, buff, strlen(buff));
<span style="white-space:pre">	</span>close(fd);


<span style="white-space:pre">	</span>return 0;<span style="white-space:pre">	</span>
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值