2021-8-15 Linux网络编程基础API

通用socket地址

要学习socket地址API,先要理解主机字节序和网络字节序

字节序概念个人理解:数据由字节的形式存在,字节在内存的排序方式就是字节序。分为大端字节序和小端字节序,大端字节序就是将一个有序列的字节逆序按照高位字节放在内存的低地址处,简而言之就是逆序放;小端字节序就是将字节的顺序按照先来后到的方式放,低位的字节放在内存的低地址处。听着还挺绕,看图!
在这里插入图片描述大端字节序称为网络字节序,小端字节序称为主机字节序,现在PC大多采用小端字节序,通常发送端总是要将数据转换成大端字节序数据再发送,所以接收端也需要看自己是否需要将数据进行转换(如果你的机器是本来就是采用大端字节序就不需要,反之就需要)

结构体sockaddr为通用socket通用地址,定义如下:

#include<bits/socket.h>
struct sockaddr
{
	sa_family_t sa_family;//地址族类型变量
	char sa_data[14];//存放socket地址值
}

常见的协议族和对应的地址族如表所示:

协议族地址族描述
PF_UNIXAF_UNIXUNIX本地域协议族
PF_INETAF_INETTCP/IPv4协议族
PF_INET6AF_INET6TCP/IPv6协议族

协议族及其地址值的相关知识,如下表

协议族地址值含义和长度
PF_UNIX文件的路径名
PF_INET16bit端口号和32bit IPv4地址,共6字节
PF_INET616bit端口号,32bit流标识,128bit IPv6地址,32bit 范围ID,共26字节

由于上一个结构体的地址值空间不够,所以Linux新定义了下面新的通用的socket地址结构体。

#include<bits/socket.h>
struct sockaddr_storage
{
	sa_family_t sa_family;
	unsigned long int __ss_align;
	char __ss_padding[128-sizeof(__ss_align)];

专用socket地址

Unix本地域协议族使用如下专用socket地址结构体:

#include<bits/socket.h>
struct sockaddr_un
{
	sa_family_t sin_family;
	char sun_path[108];
}	

IPv4 协议族专用地址结构体

#include<bits/socket.h>
struct sockaddr_in
{
	sa_family_t sin_family;//地址族:AF_INET
	u_int16_t sin_port;//端口号,要用网络字节序表示
	struct in_addr sin_port;//地址结构体
};
struct in_addr
{
	u_int32_t s_addr;
};

IPv6 协议族专用地址结构体

struct sockaddr_in6
{
	sa_family_t sin6_family;//地址族:AF_INET6
	u_int16_t sin6_port;//端口号
	u_int32_t sin6_flowinfo;//流信息
	struct in6_addr sin6_addr;//IPv6 地址结构体
	u_int32_t sin6_scope_id;//scope id
};
struct in6_addr
{
	unsigned char sa_addr[16];//IPv6地址
};

常用的IP地址转换函数

#include<arpa/inet.h>
/*将字符串表示的IP地址src转换成用网络字节序表示的ip地址,并将转换结果存储于dst指向的内存中,af为地址族AF_INET或者AF_INET6*/
int inet_pton( int af, const char* src, void* dst);
//网络字节序表示的ip地址转换成字符串表示的IP地址
const char* inet_ntop( int af,const void* src,char* dst, socklen_t cnt);
	

创建socket

#include<sys/types.h>
#include<sys/socket.h>
int socket( int domain, int type, int protocol );
//domain为底层协议族,type为指定服务类型,主要有SOCK_STREAM(流服务)和SOCK_UGRAM(数据报)服务,protocol参数是在前两个参数构成的集合下,再选择一个具体的协议,不过这个值通常都是唯一的,所以通常设置为0就可以,表示使用默认协议。此接口成功则返回一个socket文件描述符,失败返回-1并设置errno.

命名socket
在创建socket的时候我们指定了协议族,但是还没有指定那个具体的socket地址,所以我们需要将socket与socket地址进行绑定,这就是给socket命名。在服务器程序中,我们通常要命名socket,因为只有命名后客户端才知道如何连接它。客户端则通常不需要命名socket,而是采用匿名方式,即采用操作系统自动分配的socket地址。

#include<sys/types.h>
#include<sys/socket.h>
int bind( int sockfd, const struct sockaddr* my_addr,socklen_t addrlen);

bind将my_addr地址与sockfd进行绑定,成功返回0,失败-1并设置errno

监听socket

socket被命名后还不能接受与客户进行连接,还需要使用如下系统调用来创建监听队列来存放待处理的客户连接。

#include<sys/socket.h>
int listen(int sockfd, int backlog );//sockfd为被监听的socket,backlog为内核监听队列的最大长度。超过backlog,服务器将不受理新的客户连接,客户端也会收到ECONNREFUSED错误信息
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值