一、 大端字节序和小端字节序
计算机硬件有两种储存数据的方式:大端字节序(big endian)和小端字节序(little endian)。举例来说,数值0x2211使用两个字节储存:高位字节是0x22,低位字节是0x11。
大端字节序:高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。又被称为网络字节序,方便程序员检查。
小端字节序:低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。现代PC大多采用小端字节序,所以其又被称为主机字节序。
二、 核心API
1、创建socket
#include
#include
int socket(int domain, int type, int protocol)
domain:告诉系统使用哪个低层协议族;
type:指服务类型(面向流的还是字节的);
protocol:默认值为0。
socket创建成功时返回一个socket文件描述符,失败则返回-1并设置error。
2、命名socket
将一个socket与socket绑定称为给socket命名。
int bind(int sockfd, const struct sockaddr* my_addr, socklen_t addrlen)
bind将my_addr所指的socket地址分配给未命名的sockfd文件描述符,addrlen是socket地址的长度。
bind成功则返回0,失败则返回-1并设置error。
3、监听socket
首先需要系统调用来创建一个监听队列以存放待处理的客户连接:
#include
int listen(int sockfd, intbacklog)
sockfd参数指定被监听的socket。backlog参数提示内核监听队列的最大长度。
listen成功则返回0,失败则返回-1并设置error。
4、 接受连接
#include
#include
int accept(int sockfd, const sockaddr*addr,socklen_t *addrlen);
sockfd参数是执行过listen系统调用的监听socket。addr参数用来获取被接受连接的远端socket地址,该socket地址的长度由addrlen参数指出。Accept成功时返回一个新的连接socket,该socket唯一标识了被接受的这个连接,服务器可通过读写该socket来与被接受连接对应的客户通信。失败则返回-1并设置error。
5、发起连接
服务器通过listen调用被动接受连接,那么客户端需要通过connect的系统调用来主动与服务器建立连接:
#include
#include
int connect(int sockfd, const struct sockaddr*serv_addr,socklen_t addrlen);
sockfd 参数由socket 系统调用返回一个socket。serv_addr参数是服务器监听的socket地址,addrlen参数则指定这个地址的长度。
Connect成功时返回0。一旦成功建立连接,sockfd就唯一地标识了这个连接,客户端就可以通过读写socket来与服务器通信。
6、关闭连接
关闭一个连接就是关闭该连接对应的socket,可以通过关闭普通文件描述符的系统调用来完成:
#include
int close(int fd)
7、 数据读写
# include
# include (sys/socket.h)
ssize_t recv( int sockfd, void *buf, size_t len,int flags );
ssize_t send( int sockfd, const void *buf, size_t len,int flags );
Recv读取sockfd 上的数据,buf、len参数分别指定读缓冲区的位置和大小,flags通常置为0。rece成功时返回实际读取到的数据长度。recv可能返回0,这意味着通信对方已经关闭连接了。失败则返回-1并设置error。
send往sockfd上写数据,buf、len参数分别指定读缓冲区的位置和大小。send成功时返回实际读取到的数据长度,失败则返回-1并设置error。
8、 整体流程图