0. 本质
socket本质上是一种接口,用于连接网络上进程间相互的通信,每一条连接都有两个相对应的socket socket起源于"Unix"操作系统,奉行"Everything is a file(一切皆文件)"原则,工作规则为将socket作为一种文件,进行读写(调用网络I/O读写)、打开、关闭等相关操作
1. socket基础函数
1.1 socket()
创建一个socket描述符,作为参数进行读写
int socket(int domain, int type, int protocol);
1.2 bind()
将地址组的特定地址赋给socket
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
1.3 listen()
监听bind绑定的端口号
int listen(int sockfd, int backlog);
1.4 connect()
连接指定计算机的端口
int connnect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
1.5 accept()
接受连接请求,正式建立连接,
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
注意:这里的第一个参数位服务器的socket描述字,是在服务器生命周期内始终存在的,而第三个参数返回的是一个由内核自动产生的全新socket描述字,仅在连接的时间段内存在
1.6.1 read()/write()
调用网络I/O进行读写
ssize_t read(int fd, void *buf, size_t count); ssize_t write(int fd, const coid *buf, size_t count);
read调试: 读取文件描述符fd,负数为错误,0为正常,EINTR为中断,ECONNREST表示连接中断 write调试: 将buf中nbytes字节写入文件描述符fd,成功返回写入字节数,失败返回-1并设置 errno,EINTR为中断,EPIPE为网络连接中断(对方关闭连接)
1.6.2 send()/recv()
无论服务器还是客户端都使用send/recv来向 TCP 连接另一端 发送/接收 数据
int send(int sockfd, const void *buf, int len, int flags); int recv(int sockfd, void *buf, size_t len, int flags);
第二个参数为缓冲区,存放 发送/接受 的数据,第三个指明buf(第二个参数)长度,第四个一般为0
需要注意 同步,异步,阻塞,非阻塞 的关系
1.6.3 readv()/writev()
使用readv()/writev()来进行 分散读/集中写
ssize_t readv(int sockfd, const struct iovec *vector, int count); ssize_t writev(int sockfd, const struct iovec *vector,int count);
第二个参数是iovec的结构体,第三个参数规定了vector(第二个参数)的长度,即多少块内存数据需要读出/写入 sockfd
调试:成功返回 读出/写入 字节数,失败返回-1并设置 errno,此时需要error.h头文件
1.6.4 recvmsg()/sendmsg()
最常用的I/O函数,只要设置好参数,"标题1.6"内所有函数都可对应换成这两个函数调用
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags); ssize_t sendmsg(int sockfd, struct msghdr *msg,int flags);
msghdr的结构数据
struct msghdr
{
void *msg_name;
socklen_t msg_namelen;
struct iovec *msg_iov;
int msg_iovlen;
void *msg_control;
socklen_t msg_controllen;
int msg_flags;
}
1.6.5 recvfrom()/sendto()
一般用于 UDP 协议传输,但经 TCP 中connect函数调用后,也可以用于 TCP 协议传输
int sendto(int sockfd, const void *msg, int len, unsigned int flags, const struct sockaddr *to, int tolen); in trecvfrom(int sockfd, void *buf, int len, unsigned int lags, struct sockaddr *from, int *fromlen);
to:目的机的IP地址和端口号 tolen:常赋值sizeof(struct sockaddr) from:struct sockaddr 类型的变量,该变量保存源机的IP地址及端口号 fromlen:常赋值sizeof(struct sockaddr)
sendto调试:返回实际发送长度或-1(错误) recvfrom调试:返回的fromlen包含实际存入from的数据字节数,如果错误返回-1并设置相应ERRNO
1.7 close()
关闭socket描述字
int close(int fd);
close一个TCP socket的 缺省 行为时将该socket标记为关闭,然后立即返回到调用进程,该描述字将无法被调用进程使用,也就是不能再作为read或write的第一个参数使用
*注意: close操作只是使相应socket描述字引用计数-1,只用当引用计数为0时,才会触发TCP客户端向服务器发送终止连接请求.
2. 主机字节序与网络字节序
主机字节序: 引用标准有 Big-Endian 和 Little-Endian
网络字节序:在 TCP/IP 首部中,所有二进制整数在网络中传输时要求的次序
在使用时,必须要将主机字节序转换为网络字节序后,再赋给socket
3. 套接字类型
套接字的类型众多,如: DARPA Internet 地址 (Internet套接字) 本地节点的路径名(Unix套接字) CCITT X.25地址(X.25套接字) 等… 其中最具代表性的,最经典的也是最常用的为Internet套接字,而根据数据的传输方式,Internet套接字也有许多类型,如:SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET,等等… 在使用socket()创建函数时,必须指定使用哪种套接字
3.1 常用套接字
3.1.1 格流式套接字SOCK_STREAM
格流式套接字(面向连接的套接字),在代码中用SOCK_STREAM表示
SOCK_STREAM 是一种可靠的双向通信数据流,在数据传输过程中,可以保证传输数据准确无误,如损坏或者丢失,可以重新发送
- 传输中数据不会损失
- 数据按顺序传输
- 数据的收发不是同步的(不存在数据边界)
格式流套接字使用 TCP 协议保证传输保证准确性,以 IP 协议作为路由
3.1.2 数据报套接字SOCK_DGRAM
数据报套接字(无连接的套接字),在代码中用SOCK_DGRAM表示
SOCK_DGRAM 让计算机只传输数据,不做数据校验,传输过程中的任何数据的损坏和丢失,都是没法补救的,即使数据错误,也无法重传
- 强调快速传输,不保证数据的先后顺序
- 数据可能丢失与损坏
- 传输数据有大小限制
- 数据的发送与接受同步
数字报套接字使用 UDP 协议,是一种不可靠的,不按顺序传递的,以追求速度为目的的套接字,以 IP 协议作为路由
|