目录
一、套接字的地址结构
1.1 通用socket地址结构
1.2 专用socket地址结构
1.2.1 tcp协议族
1.2.3 IP协议族
二、IP地址转换函数
三、网络编程接口
3.1 socket()
3.2 bind()
3.3 listen()
3.4 accept()
3.5 connect()
3.6 close()
3.7 recv()、send()
3.8 recvfrom()、sento()
一、套接字的地址结构
我们前面所讨论的IPC机制都依靠一台计算机系统的共享资源实现,这里的资源可以是文件系统空间,共享的物理内存或者消息队列,但只有运行在同一台机器上的进程才能使用它们.
一台机器上的进程可以使用套接字和另外一台机器上的进程通信,这样就可以支持分布在网络中的客户/服务器系统.
同一台机器上的进程之间也可以使用套接字进行通信,
套接字的特性由3个属性确定,它们是:域(domain),类型(type)和协议(protocol).
套接字用地址作为它的名字,地址的格式随域(又被称为协议族,protocol family)的不同而不同,每个协议族又可以使用一个或多个地址族来定义地址格式,
1.1 通用socket地址结构
socket 网络编程接口中表示 socket 地址的是结构体 sockaddr,其定义如下:
#include <bits/socket.h>
struct sockaddr
{
sa_family_t sa_family;//协议族
char sa_data[14];//数据,没有给出IP地址,就是给了这么一块儿空间,起了一个占位的作用。
};
sa_familvy 成员是地址族类型(sa_family_t)的变量。地址族类型通常与协议族类型对应。常见的协议族和对应的地址族如下图所示:
1.2 专用socket地址结构
TCP/IP 协议族有 sockaddr_in 和 sockaddr_in6 两个专用 socket 地址结构体,它们分别用于 IPV4 和 IPV6:
- sin_family:地址族 AF INET
- sin_port:端口号,需要用网络字节序表示
- sin_addr:IPV4 地址结构:s_addr 以网络字节序表示 IPV4 地址
struct in_addr
{
u_int32_t s_addr;//无符号的32位的整型,存放IP地址;
};
1.2.1 tcp协议族
tcp协议族主要有三个:
- 地址族
- 端口号
- IP地址
//tcp协议族
struct sockaddr_in
{
sa_family_t sin_family;//地址族,就是sin_family:地址族 AF_INET
u_int16_t sin_port;//端口,16位的端口
struct in_addr sin_addr;//一个结构体,只有一个成员,是无符号的32位的整型,存放IP地址;(IPV4的地址就是32位)
//其实后面还有占位的,只是我们不用它,所以就没有写
};
1.2.3 IP协议族
//IP协议族
struct in6_addr
{
unsigned char sa_addr[16];// IPV6 地址,要用网络字节序表示
};
struct sockaddr_in6
{
sa_family_t sin6_family;//地址族:AF_INET6
u_inet16_t sin6_port;// 端口号:用网络字节序表示
u_int32_t sin6_flowinfo;// 流信息,应设置为 0
struct in6_addr sin6_addr;// IPV6 地址结构体
u_int32_t sin6_scope_id;// scope ID,尚处于试验阶段
};
二、IP地址转换函数
通常,人们习惯用点分十进制字符串表示 IPV4 地址,但编程中我们需要先把它们转化为整数方能使用,下面函数可用于点分十进制字符串表示的IPV4 地址和网络字节序整数表示的 IPV4 地址之间的转换
#include <arpa/inet.h>
in_addr_t inet_addr(const char *cp);//字符串表示的 IPV4 地址转化为网络字节序
char* inet_ntoa(struct in_addr in);// IPV4 地址的网络字节序转化为字符串表示
三、网络编程接口
头文件:
#include <sys/types.h>
#include <sys/socket.h>
3.1 socket()
socket()创建套接字,成功返回套接字的文件描述符,失败返回-1
int socket(int domain, int type, int protocol);
- domain:设置套接字的协议族,AF_UNIX 、AF_INET、 AF_INET6
- type:设置套接字的服务类型 SOCK_STREAM(流式服务)、SOCK_DGRAM(数据报服务)
- protocol:一般设置为 0,表示使用默认协议
3.2 bind()
bind()将 sockfd 与一个 socket 地址绑定,成功返回 0,失败返回-1
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
- sockfd 是网络套接字描述符,(命名套接字,就是上面的函数的返回值作为了我们的参数sockfd)
- addr 是地址结构
- addrlen 是 socket 地址的长度
3.3 listen()
listen()创建一个监听队列以存储待处理的客户连接,成功返回 0,失败返回-1
int listen(int sockfd,int backlog);
- sockfd 是被监听的 socket 套接字
- back1og 表示处于完全连接状态的 socket 的上限
3.4 accept()
accept()从 listen 监听队列中接收一个连接,成功返回一个新的连接 socket,该 socket 唯一地标识了被接收的这个连接,失败返回-1
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
- sockfd 是执行过 listen 系统调用的监听 socket
- addr 参数用来获取被接受连接的远端 socket 地址
- addrlen 指定该 socket 地址的长度
3.5 connect()
客户端需要通过此系统调用来主动与服务器建立连接,成功返回 0,失败返回-1
int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);
- sockfd 参数是由 socket()返回的一个 socket
- serv_addr 是服务器监听的 socket 地址
- addrlen 则指定这个地址的长度
3.6 close()
关闭一个连接,实际上就是关闭该连接对应的socket
int close(int sockfd);
3.7 recv()、send()
TCP 数据读写:
ssize_t recv(int sockfd, void *buff, size_t len, int flags);
ssize_t send(int sockfd, const void *buff, size_t len, int flags);
- recv()读取 sockfd 上的数据,buff 和 len 参数分别指定读缓冲区的位置和大小
- send()往 socket 上写入数据, buff 和 len 参数分别指定写缓冲区的位置和数据长度
- flags 参数为数据收发提供了额外的控制
3.8 recvfrom()、sento()
UDP 数据读写:
recvfrom()读取 sockfd 上的数据, buff 和 len 参数分别指定读缓冲区的位置和大小
ssize_t recvfrom(int sockfd, void *buff, size_t len, int flags.struct sockaddr* src_addr,socklen_t* addrlen);
- src_addr 记录发送端的 socket 地址
- addrlen 指定该地址的长度
sendto()往 socket 上写入数据, buff 和 len 参数分别指定写缓冲区的位置和数据长度
ssize_t sendto(int sockfd, void *buff, size_t len, int flags,struct sockaddr* dest_addr,socklen_t addrlen);
- dest_addr 指定接收数据端的 socket 地址
- addrlen 指定该地址的长度