【C语言】socket编程-1:理论基础

1. 理论基础

1.1 IPV4 socket 地址结构 (3大要素)

struct sockaddr_in {
    uint8_t        sin_len;
    sa_family_t    sin_family;//地址族:在这里必须设为AF_INET(代表IPV4),AF_INET6(代表IPV6)
    in_port_t      sin_port;  //端口: 0-65536 (2 bytes)
    struct in_addr sin_addr;  //IP地址:32位IPV4地址(4 bytes)
    char           sin_zero[8];
}

//通用地址结构,用来指定与socket关联的地址

struct sockaddr {
    uint8_t     sin_len;   //整个sockaddr结构体的长度
    sa_family_t sin_family;//指定该地址族
    char        sa_data[14];//由sin_family决定它的形式,这里字节为14,就是sockadd_in结构体后三个元素的长度

}

1.2 字节序

因为socket是支持异构通讯的,所以需要规定字节序,因为不同的硬件,其字节序不一致。
字节序分为:

  •   小端字节序(高位地址保存高位字节,低位地址保存低位字节),如X86
  •   大端字节序(高位地址保存低位字节,低位地址保存高位字节)

网络字节序即使用socket通讯人为规定的字节序为:大端字节序,所有通讯个体都必须转换成大端字节序发送
下面这段代码可以测试自己系统是小端还是大端

#include <stdio.h>

int main(void)
{
    unsigned int x = 0x12345678;
    unsigned char *p = (unsigned char *)&x;

    printf("%0x %0x %0x %0x\n",p[0],p[1],p[2],p[3]);
    //78 56 34 12 -> 小端字序
    //12 34 56 78 -> 大端字序
    return 0;
}

1.3 字节序转换函数

#include <arpa/inet.h> 
uint32_t htonl (uint32_t hostlong);
uint16_t htons (uint16_t hostshort);
uint32_t ntohl (uint32_t hostlong);
uint16_t ntohs (uint16_t hostshort);

其中,h代表host, n代表network; s代表short, l代表long
如 htonl -> 代表将4字节整数由主机字节序(大端或小端)转换成网络字节序(大端)
ntohl 则反之

1.4 地址转换函数

由于用户对IP地址习惯了“点分十进制”的地址,如"192.168.0.100",但是程序并不是读这个地址,而是32位的地址,
因此需要用地址转换函数来方便用户编程

#include <netinet/in.h>
#include <arpa/inet.h>
int inet_aton (const char *cp, struct in_addr *inp);//这个函数就也是将”点分十进制“地址转换成32位地址,
//只不过是转换成一个地址结构,而不是返回一个整形地址
in_addr_t inet_addr (const char *cp) //这个函数就是将”点分十进制“地址转换成32位地址
char *inet_ntoa (struct in_addr in); //将地址结构转换成”点分十进制“地址

举例:

int main(void)
{
    unsigned long addr = inet_addr ("192.168.0.100");//将”点分十进制“地址转换成32位地址
    printf("addr = %u\n", ntohl(addr));//将32位地址以主机字节序输出

    struct in_addr ipaddr;
    ipaddr.s_addr = addr;
    printf("%s\n", inet_ntoa(ipaddr));//将地址结构转换成”点分十进制“地址,应该打印”192.168.0.100“
    return 0;
    
}

1.5 socket 类型

SOCK_STREAM: tcp
SOCK_DGRAM: udp

1.6 主动套接字,被动套接字

主动套接字:调用connect()函数发起连接
被动套接字:调用accept()函数接受连接

 

2. SOCKET函数解析

2.1  socket 函数

#include <sys/socket.h>

int socket(int domain, int type, int protocol); //功能:创建一个套接字用于通信,
                                                //相当于安装了一部电话机

功能:创建一个socket套接字
//domain: 指定通信协议族,AF_INET,PF_INET 这两者是一样的
//type: SOCK_DGRAM, SOCK_STREAM
//protocol:协议类型,习惯填0,或者显式指定协议类型IPPROTO_TCP
//返回值:成功返回非负整数,失败返回-1

2.2 bind 绑定函数 

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

功能:绑定一个本地地址到套接字
//sockfd: socket函数返回的套接字
//addr: 要绑定的地址
//addrlen: 地址长度
//返回值:成功返回0,失败返回-1

2.3 listen 监听函数 

int listen(int sockfd, int backlog)

功能:将套接字用于监听进入的连接,将套接字由close转换成listen状态,转换成监听状态之后才能连接
//sockfd: socket函数返回的套接字
//backlog:规定内核为此套接字排队的最大连接个数,能够并发连接的数目,其值等于 已完成连接队列数+未完成队列数(三次握手未成功) 之和
//返回值:成功返回0,失败返回-1

2.4 accept 函数 

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

功能:从已完成连接队列中返回第一个连接,如果已完成连接队列为空(说明没有三次握手成功的套接字),则阻塞
//sockfd: 服务器套接字
//addr: 将返回对等方的套接字地址
//addrlen: 返回对等方的套接字地址长度
//返回值:成功返回非负整数,失败返回-1
//相当于将对方来电号码填充进来,accpet函数会返回一个已连接套接字

2.5 connect 函数 

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)

功能:建立一个连接至addr所指定的套接字
//sockfd: 未连接套接字
//addr: 要连接的套接字地址
//addrlen: 第二个参数addr长度
//返回值:成功返回0,失败返回-1

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值