socket和TCP/IP协议族的关系
- 数据链路层、网络层、传输层协议是在内核中实现的。
- 因此操作系统需要实现一组系统调用,使得应用程序能够访问这些协议提供的服务。
- 实现这组系统调用的API(Application Programming Interface,应用程序编程接口)主要有两套: socket和XTI. XTI现在基本不再使用
图1-1显示了socket与TCP/IP协议族的关系。
由socket定义的这一组 API提供如下两点功能:
- 将应用程序数据从用户缓冲区中复制到TCP/UDP内核发送缓冲区,以交付内核来发送数据(比如send函数),或者是从内核TCP/UDP接收缓冲区中复制数据到用户缓冲区,以读取数据;
- 应用程序可以通过它们来修改内核中各层协议的某些头部信息或其他数据结构,从而精细地控制底层通信的行为。比如可以通过setsockopt函数来设置IP数据报在网络上的存活时间。
- socket 是一套通用网络编程接口,它不但可以访问内核中TCP/IP协议栈,而且可以访问其他网络协议栈(比如X.25协议栈、UNIX本地域协议栈等)。
#include <sys/types.h>
#include <sys/socket.h>
头文件
#include <arpa/inet.h>
in_addr_t inet_addr(const char *cp);
//字符串表示的 IPV4 地址转化为网络字节序
char* inet_ntoa(struct in_addr in);
// IPV4 地址的网络字节序转化为字符串表示
IP 地址转换函数
- 通常,人们习惯用点分十进制字符串表示 IPV4 地址,但编程中我们需要先把它们转化为整数方能使用,上面的函数可用于点分十进制字符串表示的 IPV4 地址和网络字节序整数表示的 IPV4 地址之间的转换:
. int socket(int domain, int type, int protocol);
1.创建套接字
- socket()创建套接字,成功返回套接字的文件描述符,失败返回-1
- domain: 设置套接字的协议簇, AF_UNIX AF_INET AF_INET6
- type: 设置套接字的服务类型 SOCK_STREAM(TCP) SOCK_DGRAM(UDP)
- protocol: 一般设置为 0,表示使用默认协议
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
2.绑定
- bind()将 sockfd 与一个 socket 地址绑定,成功返回 0,失败返回-1
- sockfd 是网络套接字描述符
- addr 是地址结构
- addrlen 是 socket 地址的长度
int listen(int sockfd, int backlog);
3.监听
- listen()创建一个监听队列以存储待处理的客户连接,成功返回 0,失败返回-1
- sockfd 是被监听的 socket 套接字
- backlog 表示处于完全连接状态的 socket 的上限
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
4.接收
- accept()服务器从 listen 监听队列中接收一个连接,成功返回一个新的连接 socket 该 socket
唯一地标识了被接收的这个连接,失败返回-1 - sockfd 是执行过 listen 系统调用的监听 socket
- addr 参数用来获取被接受连接的远端 socket 地址
- addrlen 指定该 socket 地址的长度
int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);
5.连接
- connect()客户端需要通过此系统调用来主动与服务器建立连接 成功返回 0,失败返回-1
- sockfd 参数是由 socket()返回的一个 socket
- serv_addr 是服务器监听的 socket 地址
- addrlen 则指定这个地址的长度
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);
6.TCP 数据读写
- recv()读取 sockfd 上的数据,buff 和 len 参数分别指定读缓冲区的位置和大小
. 返回值:失败时,返回值小于0;超时或对端主动关闭,返回值等于0;成功时,返回值是返回接收数据的长度。 - send()往 socket 上写入数据,buff 和 len 参数分别指定写缓冲区的位置和数据长度
- flags 参数为数据收发提供了额外的控制
ssize_t recvfrom(int sockfd, void *buff, size_t len, int flags,
struct sockaddr* src_addr, socklen_t *addrlen);
ssize_t sendto(int sockfd, void *buff, size_t len, int flags,
struct sockaddr* dest_addr, socklen_t addrlen);
7.UDP 数据读写
- recvfrom()读取 sockfd 上的数据,buff 和 len 参数分别指定读缓冲区的位置和大小 src_addr 记录发送端的
socket 地址 addrlen 指定该地址的长度 sendto()往 socket 上写入数据,buff 和 len参数分别指定写缓冲区的位置和数据长度 - dest_addr 指定接收数据端的 socket 地址
- addrlen 指定该地址的长度
int close(int sockfd);
int shutdown(int sockfd,int howto);
8.关闭
- close()关闭一个连接,实际上就是关闭该连接对应的 socket,不过并不是立即关闭连接,而是将fd的引用计数减1,当fd的引用计数为0时,才真正关闭。
- shutdown()是立即终止连接。
图论
Linux高性能服务器编程