socket编程之结构体解析

本文章主要讲解linux网络编程socket通讯中常用到的结构体组成和作用

下图为各个结构间的对应关系(图来源于“爱编程的大丙”)
socket编程之结构体解析

1.结构体sockaddr:

/************************************
**sa_family : 地址协族议,常用值:AF_INET(网络通讯) / AF_UNIX(linux 本地通讯)
**sa_data : 该数组存储网络端口port,IP地址(网络字节序),多出内存保留
*************************************/
struct sockaddr
{
	unsigned  short  sa_family;     /* address family, AF_xxx:地址族协议 */
	char  sa_data[14];              /* 14 bytes of protocol address:// 端口(2字节) + IP地址(4字节) + 填充(8字节)*/
};

该结构体 struct sockaddr一般用于以下socket通讯api函数

int bind(int sockfd, const struct sockaddr * my_addr, socklen_t addrlen);

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

int connect(int soctfd, const struct sockaddr * addr, int addrlen);

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                 struct sockaddr *src_addr, socklen_t *addrlen);

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
               const struct sockaddr *dest_addr, socklen_t addrlen);

用户一般不会直接使用结构体struct sockaddr,通常使用结构体 struct sockaddr_in或者 struct sockaddr_un强制转换成struct sockaddr 类型使用;例如下面函数使用:

struct sockaddr_in servaddr;

memset(&servaddr, 0, sizeof(servaddr) );
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr(SERVER_IP);
servaddr.sin_port = htons(8888);
if(connect(socketfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0 )
{
	perror("socket connect failed!");
	return -1;
}

2.结构体 struct sockaddr_in

typedef unsigned short  	uint16_t;
typedef unsigned int    	uint32_t;
typedef uint16_t 			in_port_t;
typedef uint32_t 			in_addr_t;
typedef unsigned short int  sa_family_t;
#define __SOCKADDR_COMMON_SIZE (sizeof (unsigned short int))

struct in_addr
{
    in_addr_t s_addr;
};  

// sizeof(struct sockaddr) == sizeof(struct sockaddr_in)
struct sockaddr_in
{
    sa_family_t 	sin_family;			/* 地址族协议: AF_INET*/
    in_port_t 		sin_port;         	/* 端口, 2字节-> 大端(网络字节序)  */
    struct 			in_addr sin_addr;   /* IP地址, 4字节 -> 大端(网络字节序)  */
    unsigned char 	sin_zero[8];		/* 填充 8字节 */
}; 

结构体 struct sockaddr_in适用于socket 网络套接字通讯

3.结构体struct sockaddr_un

typedef unsigned short int  sa_family_t;

 struct sockaddr_un 
 {
	sa_family_t sun_family; /*地址族协议:PF_UNIX或AF_UNIX */
	char sun_path[108]; 	/* 路径名 */
 };

结构体struct sockaddr_un适用于本地进程间通讯的UNIX套接字通讯。进程间通信的一种方式是使用UNIX套接字,人们在使用这种方式时往往用的不是网络套接字,而是一种称为本地套接字的方式。这样做可以避免为黑客留下后门。使用UNIX套接字跟使用网络套接字类似,只需将变量参数 struct sockaddr_in 换成struct sockaddr_un输入到响应的socket套接字api函数上即可,如下所示:

/****************************** socket 网络套接字通讯 ******************************/

struct sockaddr_in server;
int listenfd
socklen_t len;

if( (socketfd = socket(AF_INET, SOCK_STREAM, 0) ) ==  -1)	//socket函数类似于open函数,打开并创建一个socket,AF_INET使用IPV4协议族,SOCK_STREAM为TCP套接口
{
	perror("socket create failed!");
	return -1;
}

memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;					//IPV4协议
server.sin_port   = htons(8888);				//端口号
server.sin_addr.s_addr  = htonl(INADDR_ANY);	//自动生成自身IP做服务器IP给客户端连接

len = sizeof(struct sockaddr);
if(bind(listenfd, (struct sockaddr *)&server, len)<0)	//绑定
{
	perror("bind error.");
	return -1;
}
........		/*省略后续socket api函数配置*/


/****************************** socket UNIX套接字通讯 ******************************/
struct sockaddr_un server;
int listenfd;

if( (listenfd = socket(AF_UNIX, SOCK_STREAM, 0) ) ==  -1)	//进程间socket UNIX套接字通讯
{
	perror("socket create failed!");
	return -1;
}
memset((void*)&server,0,sizeof(struct sockaddr_un));
server.sun_family = AF_UNIX;
strcpy(server.sun_path, "/tmp/testsocketUNIX");
unlink(server.sun_path);

if(bind(listenfd, (struct sockaddr*)&server, sizeof(server)) < 0)
{
	perror("fail to bind");
	return NULL;
}
........		/*省略后续socket api函数配置*/
上一篇:堆知识--持续


下一篇:C语言错误 error C2059: 语法错误:“)” 以及 错误 error C2065: “sockaddr”: 未声明的标识符