socket编程(一)

什么是socket

1.socket可以看成是用户进程与内核网络协议栈的编程接口。

2.socket不仅可以用于本机的进程间通信,还可以用于网络上不同主机的进程间通信。


当一台主机的应用程序想发给另一台主机的应用程序,这时候的数据实际上是从下到上,再从上到下的一个过程。但是从逻辑上可以看成双方是进行对等通信的(Application和Application定义了一个逻辑链路进行数据通讯)。

底层那部分已经被内核实现了,也就是TCP/IP协议栈已经属于内核的一部分了,应用层是用户要实现的,它属于用户进程的部分,也就是工作在用户空间,用户空间中的程序要想访问内核,使用内核的服务,就需要通过一定的接口来访问它,这个接口就称为套接口,所以socket可以看成是用户进程与内核网络协议栈的编程接口。

从通信的角度上来看,套接口实现了将应用程序的数据传递给对等方的应用程序。

如下图:

应用程序A要将数据传递给应用程序B,它是通过socket来传输的,这是从逻辑上来看的通信过程,屏蔽了底层的一些实际的传输方式。所以可以把套接口看成一种抽象,两个进程之间进行数据传递的抽象,这个抽象使得我们不会关心底层的传输细节,我们只需关心套接口的存在即可


并且套接口是全双工的通信方式,既可以从A主机到达B主机,也可以从B主机到达A主机。所以说socket不仅可以用于本机的进程间通信,还可以用于网络上不同主机的进程间通信。

并且,套接口还可以在异构系统间进行通信,比如在手机上的QQ和在PC上的QQ进行通讯,两者的硬件结构和软件都可以不相同。

IPv4套接口地址结构

套接口既然能够连接两台机器码,那么套接口就必须拥有一定的属性,要有地址的属性来标识一个端点,对等方也同样要有这个属性。可以把套接口看成电话机,肯定必须都拥有电话号码才能进行连接。

struct sockaddr_in{
     uint sin_len;//整个sockaddr_in结构体的长度
     sa_family_t sin_family;//指定该地址家族,在这里必须设为AF_INET
     in_port_t sin_port;//端口
     struct in_addr sin_addr;//IPv4的地址
     char sin_zero[8];//暂不使用,一般将其设置为0
};

为什么要有地址族的概念,因为socket在设计的时候不仅仅能够用在TCP/IP协议,还能用于其他协议,比如UNIX域协议,所以必须指定地址家族,一旦指定地址家族为AF_INET,说明采用的是IPv4协议。

地址是用一个结构体来表示,IPv4协议地址是32位,实际上结构体中只有一个成员,无符号的32位整数,端口号是16的无符号整数。

struct in_addr{
    unit32_t s_addr;//网络字节序
};

通用地址结构

通用地址结构用来指定与套接字关联的地址

struct sockaddr{
    unit8_t sin_len;//整个sockaddr结构体的长度
    sa_family_t sin_family;//指定该地址家族
    char sa_data[14];//又sin_family决定它的形式
}

为什么要有通用地址结构,因为套接口不仅能用于TCP/IP编程,还能用于UNIX域编程,不同的协议地址结构可能不同,这个结构可以用于任何协议的套接口编程。

上面两个地址结构是兼容的。

网络字节序

1.字节序

大端字节序

    最高有效位存储于最低内存地址处,最低有效位存储于最高内存地址处。

小端字节序

    最高有效位存储于最高内存地址处,最低有效位存储于最低内存地址处。

这个整数在内存中的存储形式有两种。


为什么要有字节序的概念,因为socket能够实现异构系统间通信,不同的硬件平台对同一个整数的存放形式是不一样的,有的机器采用大端字节序,有的机器采用小端字节序存放。那么当一整数传输至对等方,有可能无法解析,字节序不同,导致解析出来的数据相反。所以必须统一字节序,将数据传输的时候统一为一个字节序,统一出来的这个字节序称为网络字节序(规定为大端字节序)。主机的字节序有可能是大端,也有可能是小端。所以先转成网络字节序。

2.主机字节序

不同的主机有不同的字节序,如X86为小端字节序,ARM字节序是可配置的。

3.网络字节序

网络字节序规定大端字节序

字节序转换函数

uint32_t htonl(uint32_t hostlong);//将4个字节的整数,由主机字节序转换成网络字节序
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
说明:在上述的函数中,h代表host;n代表network;s代表short;l代表long

地址转换函数

我们人为能够认识的地址不是32位的地址,我们比较习惯的地址是点分十进制的形式。比如192.168.0.100,编程的时候更多指定的是32位地址整数,所以需要引入地址转换函数。

int inet_aton(const char *cp,struct in_addr *inp);//和下面一个作用一样,输出到参数
int_addr_t inet_addr(const char *cp);//将点分十进制的IP地址转化成32位的整数
char *inet_ntoa(struct in_addr in);//将一个地址结构转换成点分十进制的IP地址

套接字类型

1.流式套接字(SOCK_STREAM)

提供面向连接的、可靠的数据传输服务,数据无差错,无重复的发送,且按发送顺序接受。对应的就是TCP协议。

2.数据报式套接字(SOCK_DGRAM)

提供无连接服务。不提供无错保证,数据可能丢失或重复,并且接收顺序混乱。对应的就是UDP协议。

3.原始套接字(SOCK_RAW)


猜你喜欢

转载自blog.csdn.net/wk_bjut_edu_cn/article/details/80377636