socket编程--socket基本概念

时间:2022-12-15 08:26:09

socket
socket可以看成是用户进程与内核网络协议栈的编程接口,不仅可以用于本机的进程间通信,也可以用于网络上不同主机的进程间通信—而管道只能在同一台主机进行通信

应用层依靠socket进行数据传输,我们不必关心底层的内核,即底层数据的传输细节,只关心套接口的存在。

可以把套接口看成进程间的通信,主机A上的进程通过套接口传输数据到主机B的进程。

IPv4套接字地址结构

struct sockaddr_in{ 
    uint8_t sin_len;  /*length of the structure*/
    sa_family_t sin_family;  /*AF_INET*/
    in_port_t sin_port;     /*16bits TCP or UDP port number*/
    struct in_addr sin_addr;  
    char sin_zeor[8];   /*unused*/
};

说明:sin_len:整个sockaddr_in结构体的长度
sin_family:指定该地址家族,在这里必须设为AF_INET – IPv4
sin_port:端口
sin_addr:IPv4地址
sin_zero:暂不使用,一般将其设为0
其中,结构体in_addr:

struct in_addr {
    in_addr_t s_addr;
};

结构体in_addr用来表示一个32位的IPv4地址–字节序为网络字节序
通用地址结构
通用地址结构用来指定与套接字关联的地址

struct sockaddr{ 
    uint8_t sin_len;   
    sa_family_t sin_family;  /*AF_INET*/
    char da_data[14];
};

说明:sin_len:整个sockaddr结构体的长度
sin_family:指定该地址家族
sa_data:由sin_family决定它的形式

可看到:通用地址结构中的da_data有14个字节和IPv4 sin_port(2字节)、sin_addr(4字节)、sin_zero(8字节)相同,说明这两个兼容,通常,进行TCP/IP编程时跟多的是填充IPv4套接口地址结构,然后强制转换为通用地址结构。

网络字节序

字节序
1、大端字节序(Big EndIan)
最高有效位存储在最低内存地址处,最低有效位存储在最高内存地址处
2、小端字节序(Little EndIan)
最高有效位存储在最高内存地址处,最低有效位存储在最低内存地址处
主机主机序
不同主机有不同的字节序,如x86位小端字节序,Motorola 6900为大端字节序,ARM字节序为可配置的
网络字节序
网络字节序规定为大端字节序
socket编程--socket基本概念
为什么要引入字节序这个概念?
socket能够实现异构系统间通信,不同系统字节序不同,引入字节序可实现异构系统通信
测试主机大小端:
int main()
{
unsigned int x = 0x12345678;
unsigned char p = (unsigned char )&x;
printf(“%0x %0x %0x %0x”, p[0],p[1],p[2],p[3]);
return 0;
}
socket编程--socket基本概念
高地址存高内存地址—小端字节序
字节序转换函数
uint32_t htonl(uint32_t hostlong); //将4个字节的主机字节序转换为网络字节序
uint32_t htons(uint32_t hostshort);//2个字节的主机字节序转换为网络字节序
uint32_t ntohl(uint32_t netlong); //相反
uint32_t ntohs(uint32_t netshort);
说明:h代表host;n代表network
s代表short;l代表long

int main()
{
        unsigned int x = 0x12345678;
        unsigned char *p = (unsigned char *)&x;
        printf("%0x %0x %0x %0x\n", p[0],p[1],p[2],p[3]);

        unsigned int y = htonl(x);
        p = (unsigned char*)&y;
        printf("%0x %0x %0x %0x\n", p[0], p[1], p[2], p[3]);
        return 0;
}

socket编程--socket基本概念
主机字节序转换为了网络字节序(大端字节序)

地址转换函数

in_addr_t inet_addr (const char *cp);
inet_addr将一个点分十进制IP地址字符串转换成32位数字表示的IP地址(网络字节顺序)。

char* inet_ntoa (struct in_addr in);
inet_ntoa将一个32位数字表示的IP地址转换成点分十进制IP地址字符串。

这两个函数互为反函数
unsigned char *ip = “192.168.1.120”;
int int_ip = inet_addr(ip);
printf(“%d\n”, int_ip);

    struct in_addr ipaddr ;
    ipaddr.s_addr = int_ip;
    printf("%s\n", inet_ntoa(ipaddr));

套接字类型

(1)流式套接字 SOCK_STREAM — TCP
提供面向连接、可靠的数据传输服务,数据按字节流、按顺序收发,保证在传输过程中无丢失、无冗余。TCP协议支持该套接字。

(2)数据报套接字 SOCK_DGRAM – UDP
提供面向无连接的服务,数据收发无序,不能保证数据的准确到达。UDP协议支持该套接字。

(3)原始套接字 SOCK_RAW
允许对低于传输层的协议或物理网络直接访问,例如可以接收和发送ICMP报文。常用于检测新的协议。