socket: 插座;套接字
SOCK_STREAM:流格式套接字,面向连接的套接字,使用TCP协议
SOCK_DGRAM:数据报格式套接字,无连接的套接字,使用UDP协议
IP地址:Internet Protocol Address 网际协议地址
MAC地址:Media Access Control Address 媒体访问控制地址
socket()
int socket(int af, int type, int protocol); //Linux下创建套接字
af: Address Family, 地址族,AF_INET(IPv4), AF_INET6(IPv6)
pf: Protocol Family, 协议族,PF_INET(IPv4), PF_INET6(IPv6)
type: SOCK_STREAM、SOCK_DGRAM...
protocol: IPPROTO_TCP、IPPROTO_UDP...
SOCKET socket(int af, int type, int protocol); //Windows下创建套接字
bind()
int bind(int sock, struct sockaddr *addr, socklen_t addrlen); //Linux服务器绑定套接字
sock: socket文件描述符
addr: 为sockaddr结构体变量的指针,sockaddr由sockaddr_in强制转换
addrlen: 为addr变量的大小
图一 sockaddr_in结构体
sockaddr_in专门用来保存IPv4地址的结构体
sin_family: Address Family,socket的地址族
sin_port: 16位的端口号
sin_addr: 结构体in_addr,32位IP地址
sin_zerp: 8个字节的0
图二 sockaddr_in转换为sockaddr
sockaddr专门用来保存多种类型的IP地址和端口号
sockaddr_in和sockaddr的字节数相同
int bind(SOCKET sock, const struct sockaddr *addr, int addrlen); //Windows服务端绑定套接字
connect()
int connect(int sock, struct sockaddr *serv_addr, socklen_t addrlen); //Linux客户端连接套接字
int conncet(SOCKET sock, const struct sockaddr *serv_addr, int addrlen); //Windows客户端连接套接字
listen()
int listen(int sock, int backlog); //Linux服务端监听套接字
sock为需要进入监听状态的套接字
backlog为请求队列的最大长度
Request Queue: 请求队列,存放请求的缓冲区
int listen(SOCKET sock, int backlog); //Windows服务端监听套接字
accept()
int accept(int sock, struct sockaddr *addr, socklen_t *addrlen); //Linux服务端接受客户端请求
SOCKET accept(SOCKET sock, struct sockaddr *addr, int *addrlen); //Windows服务端接受客户端请求
Linux下数据的接收和发送
ssize_t write(int fd, const void *buf, size_t nbytes); //Linux下向套接字中写入数据
ssize_t: signed int 有符号整型
fd: 要写入的文件描述符
buf: 要写入的数据的缓冲区地址
nbytes: 要写入的数据的字节数
ssize_t read(int fd, void *buf, size_t nbytes); //Linux下从套接字中读取数据
Windows下数据的接收和发送
int send(SOCKET sock, const char *buf, int len, int flags); //从Windows服务器端发送数据
sock为要发送数据的套接字
buf为要发送的数据的缓冲区地址
len为要发送的数据的字节数
flages为要发送数据时的选项,通常为0或NULL
int recv(SOCKET sock, char *buf, int len, int flags); //在客户端接收数据
关闭socket
int close(int sockfd); //Linux下关闭socket文件
sockfd:socket文件描述符
closesocket(SOCKET sock); //Windows下关闭socket
close()/closesocket()会向服务器端发送FIN包,不管输出缓冲区是否有数据,会直接将socket从内存中清除。
shutdown()
int shutdown(int sock, int howto); //Linux下单方面断开数据传输通道
sock:需要断开的socket
howto:断开方式。SHUT_RD:断开输入流;SHUT_WR:断开输出流;SHUT_RDWR:同时断开I/O流。
int shutdown(SOCKET sock, int howto); //Windows下单方面断开数据传输通道
sock:需要断开的socket
howto:断开方式。SD_RECEIVE:关闭接收操作;SD_SEND:关闭发送操作;SD_BOTH:同时关闭接收和发送操作。
shutdown()会等输出缓冲区中的数据传输完毕再发送FIN包,但不关闭socket,socket依然存在
字节序
大端序(Big Endian):高位字节存放到低位字节
图三 整数0x12345678的大端序字节表示
小端序(Little Endian):高位字节存放到高位地址
图四 整数0x12345678的小端序字节表示
htons(): host to network short,将short类型数据从主机字节序转换为网络字节序
ntohs(): network to host short,将short类型数据从网络字节序转换为主机字节序
htonl(): host to network long,将long类型数据从主机字节序转换为网络字节序
ntohl(): network to host long,将long类型数据从网络字节序转换为主机字节序
inet_addr(): 将IP地址的字符串转换为32位整数,同时进行网络字节序转换
gethostbyname()
通过域名获取IP地址
sendto()
ssize_t sendto(int sock, void *buf, size_t nbytes, int flags, struct sockaddr *to, socklen_t addrlen); //Linux下UDP发送数据
sock:套接字
buf:保存待输出数据的缓冲区地址
nbytes:待输出数据的长度(字节单位)
flags:可选参数,若没有为0
to:存有目标地址信息的sockaddr结构体变量的地址
addrlen:传递给参数to的地址值结构体变量的长度
int sendto(SOCKET sock, const char *buf, int nbytes,int flags, const struct sockaddr *to, int addrlen); //WIndows下UDP发送数据
recvfrom()
ssize_t recvfrom(int sock, void *buf, size_t nbytes, int flags, struct sockaddr *from, socklen_t *addrlen); //Linux下UDP接收数据
sock:套接字
buf:保存接收数据的缓冲区地址
nbytes:可接受的最大字节数
flags:可选项参数,若没有则为0
from:存有发送端地址信息的sockaddr结构体变量的地址
addrlen:保存参数from的结构体变量长度的变量地址值
int recvfrom(SOCKET sock, char *buf, int nbytes, int flags, const struct sockaddr *from, int *addrlen); //Windows下UDP接收数据