基于Linux的文件操作
- Linux中,一切都是文件,socket也是文件的一种,因此网络传输中也可以使用I/O函数。
- 文件描述符是系统分配给文件或socket的整数,相当于文件的ID
文件描述符 | 对象 |
---|---|
0 | 标准输入 |
1 | 标准输出 |
2 | 标准错误 |
打开文件
int open(const char *path, int flag);
- path:文件地址
- flag:文件打开模式
- 成功时返回文件描述符, 失败时返回-1
打开模式 | 含义 |
---|---|
O_CREAT | 必要时创建文件 |
O_TRUNC | 删除全部现用数据 |
O_APPEND | 添加数据 |
O_RDONLY | 只读 |
O_WRONLY | 只写 |
O_RDWR | 读写 |
关闭文件
int close(int fd);
- 成功时返回0, 失败时返回-1
- fd:文件描述符
写入操作
ssize_t write(int fd, const void *buf, size_t nbytes);
- 成功时返回写入的字节数,失败时返回-1
- fd: 写入对象的文件描述符
- buf:保存传输数据的缓冲地址值
- nbytes:传输数据的字节数
读取操作
ssize_t read(int fd, void *buf, size_t nbytes);
- 成功时返回读取的字节数, 失败时返回-1
socket
socket类型与协议
- 协议就是为了实现数据交换的约定;
- PF_INET对应IPv4互联网协议族,PF_INET6对应IPv6互联网协议族;
- socket类型也就是数据传输方式,有基于TCP面向连接的SOCK_STREAM和基于UDP面向消息的SOCK_DGRAM;
创建socket
int socket(int domain, int type, int protocol);
- domain:协议族信息
- type:数据传输类型信息
- protocol:通信中要使用的协议信息,数据传输方式相同但协议不同时,需要单独指定第三个参数
TCP socket
int tcp_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
int tcp_socket = socket(PF_INET, SOCK_STREAM, 0);
- 由于满足PF_INET和SOCK_STREAM的只有IPPROTO_TCP,因此第三个参数可以省略
UDP socket
int udp_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
int udp_socket = socket(PF_INET, SOCK_DGRAM, 0);
地址族与数据序列
表示IPv4地址的结构体
struct sockaddr_in {
sa_family_t sin_family; // 地址族
unit16_t sin_port; // 16位TCP/UDP端口号
struct in_addr sin_addr; // 32位IP地址
char sin_zero[8]; // 不使用
}
struct in_addr {
In_addr_t s_addr;
}
- sin_family
地址族 | 含义 |
---|---|
AF_INET | IPv4中采用的地址族 |
AF_INET6 | IPv6中采用的地址族 |
AF_LOCAL | 本地通信采用的UNIX协议的地址族 |
- sin_port:以网络字节序(大端)保存
- sin_addr:以网路字节序保存
网络字节序与地址变换
- 大端序: 高位字节存放到低位地址
- 小端序:高位字节存放到高位地址
- 网络字节序为大端序
- Intel和AMD系列CPU都采用小端序
字节序转换
unsigned short htons(unsigned short);
unsigned short ntohs(unsigned short);
unsigned long htons(unsigned long);
unsigned long ntohs(unsigned long);
- h表示host字节序
- n表示network字节序
除了向sockaddr_in结构体变量填充数据需要考虑字节序转换问题,其他情况不需要考虑。
网络地址的初始化与分配
- 将字符串信息转换为网络字节序
in_addr_t inet_addr(const char *string);
- 成功时返回32位大端序整数性值,失败时返回INADDR_NONE
下面这种形式更常用!
int inet_aton(const char *string, struct in_addr *addr);
- 成功时返回1, 失败时返回0
- string: 字符串地址
- addr:将保存转换结果的in_addr结构体变量的地址值
- 网络地址序转换为字符串地址
char *inet_ntoa(struct in_addr addr);
- 成功时返回字符串地址值,失败时返回-1
网络地址初始化
- 服务器端
struct sockaddr_in serv_adr, clnt_adr;
memset(&serv_adr, 0, sizeof(serv_adr));
serv_adr.sin_family = AF_INET;
serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_adr.sin_port = htons(atoi(argv[1]));
利用常数INADDR_ANY分配服务器端的ip地址,即可以自动获取运行服务器端的ip
- 向socket分配网络地址
int bind(int sockfd, struct sockddr *myaddr, socklen_t addrlen);
- 成功时返回0, 失败时返回-1
- sockfd:要分配地址信息的socket文件描述符
- myaddr:存有地址信息的结构体变量地址值
- addrlen:myaddr的长度