网络编程
进程间通信-Socket套接字
基本特点
- Socket是一种接口技术,被抽象成一个文件操作,可以让同一计算机中的不同进程之间通信,也可以让不同计算机的进程之间进行通信(网络)
同一计算机中的socket进程间通信
-
底层需要借助socket文件,进行在同一计算机下的进程间通信
-
#include <sys/types.h> #include <sys/socket.h> int socket(int domain,int type,int protocol); // 功能:创建socket文件 /* domain: AF_UNIX,AF_LOCAL 本地通信(进程间通信) AF_INET 基于IPv4地址网络通信 AF_INET6 基于IPv6地址网络通信 */ /* type: SOCK_STREAM 数据流协议(本地只有数据流协议) SOCK_DGRAM 数据报协议 */ // protocol:特殊通信协议,一般不用,写0即可 // 返回值:成功返回socket描述符,失败返回-1 int bind(int sockfd,const struct sockaddr *addr,socklen_t addrlen); // 功能:绑定socket描述符与通信地址 // socketfd:socket描述符 /* addr:地址结构体 实际传递的是socketaddr_un 或者 socketaddr_in结构体地址,但是最终都要把它们转换成socketaddr*,因为C语言不支持自建类型自动识别转换,因此要强转 // 本地通信地址结构 #include <sys/un.h> struct sockaddr_un { __kernel_sa_family_t sun_family;// 地址簇 domain的值 char sun_path[UNIX_PATH_MAX]; // socket文件路径 }; // 网络通信地址结构 #include <netinet/in.h> struct sockaddr_in { __kernel_sa_family_t sin_family;// 地址簇 domain的值 in_port_t sin_port; // 端口号 struct in_addr sin_addr; // IP地址结构体 ... } */ // addrlen:通信地址结构体的字节数,用于区分socketaddr_un还是socketaddr_in // 返回值:成功返回0,失败返回-1 // 注意:如果是本地通信,只有当bind成功后才会创建socket文件完成 int listen(int sockfd,int backlog); // 功能:监听socket,只有数据流协议时才需要使用 // socketfd:socket描述符 // backlog:监听等待连接的排队数量,一般默认最大128 // 返回值:成功返回0,失败返回-1 int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen); // 功能:等待连接,只有数据流协议时才需要使用 // socketfd:socket描述符 // addr:获取连接者的通信地址(socketaddr_un\socketaddr_in) // addrlen:获取地址结构体的大小 // 返回值:连接成功时返回一个新的socket描述符,用于与连接者进行通信 // 注意:如果没有人要连接过来,该函数会阻塞等待 int connect(int sockfd,const struct sockaddr *addr,socklen_t addrlen); // 功能:连接socket,数据流使用 // sockfd:socket描述符 // addr:要连接的目标地址 // addrlen:通信地址结构体字节数 // 返回值:连接成功返回0,失败返回-1 ssize_t recv(int sockfd,void *buf,size_t len,int flags); // 功能:从socket中读取数据,数据流中使用 // socketfd:建立连接后的新的socket描述符 // buf:存储数据的内存首地址 // len:存储数据内存的字节数 /* flags:一般写0即可 MSG_DONTWAIT 不阻塞 */ // 返回值:成功接收到的字节数,-1表示出现错误,0表示断开连接 ssize_t send(int sockfd,const void *buf,size_t len,int flags); // 功能:向socket发送数据,数据流中使用 // socketfd:建立连接后的新的socket描述符 // buf:待发送数据的内存首地址 // len:要发送的数据的字节数 /* flags:一般写0即可,阻塞 MSG_DONTWAIT 不阻塞 */ // 返回值:成功接收到的字节数,-1表示出现错误 // 注意:如果不需要额外的发送、接收功能,read\write也可以进行发送和接受
#include <unistd.h> int close(int fd); // 功能:关闭socket
socket本地通信编程模型
进程A | 进程B |
---|---|
创建socket对象 | 创建socket对象 |
准备通信地址 | 准备通信地址(socket文件路径) |
绑定socket和通信地址 | … |
监听 | … |
等待连接 | 发起连接 |
接收\发送数据 | 发送\接收数据 |
关闭socket | 关闭socket |
删除socket文件 | … |
网络编程
- 底层遵循的是TCP\IP协议,在系统层是以Socket接口方式呈现
基于TCP协议的网络通信模型
服务端 | 客户端 |
---|---|
创建socket对象 | 创建socket对象 |
准备通信地址(本机ip地址+端口号) | 准备通信地址(服务器公网ip地址+端口号) |
绑定socket和通信地址 | … |
设置监听和排队数量 | … |
等待客户端连接 | 连接服务端 |
分配新的socketfd+开进程或者线程 | … |
接收请求 | 发送请求 |
响应请求 | 接受响应 |
关闭新socket | 关闭socket |
TCP使用到的函数
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain,int type,int protocol);
// 功能:创建socket文对象
// domain:AF_INET 基于IPv4地址网络通信
// type:SOCK_STREAM 数据流协议(本地只有数据流协议)
// protocol:特殊通信协议,一般不用,写0即可
// 返回值:成功返回socket描述符,失败返回-1
int bind(int sockfd,const struct sockaddr *addr,socklen_t addrlen);
// 功能:绑定socket描述符与通信地址
// socketfd:socket描述符
/* addr:地址结构体
实际传递的是socketaddr_in结构体地址,但是最终都要把它转换成socketaddr*,因为C语言不支持自建类型自动识别转换,因此要强转
// 网络通信地址结构
#include <netinet/in.h>
struct sockaddr_in
{
__kernel_sa_family_t sin_family;// 地址簇 domain的值
__be16 sin_port; // 端口号 大端数据
struct in_addr sin_addr; // IP地址结构体 大端数据
}
struct in_addr
{
__be32 s_addr;// 大端的int整数
};
// 服务器公网ip:47.97.229.46 不会变
// 服务器本地ip:172.16.83.85 可能会变
// 服务名:student
// 密码:zzxx
// 端口号:9999以内 可以设置
// addrlen:通信地址结构体的字节数
// 返回值:成功返回0,失败返回-1
点分十进制的ip地址转换成4字节的大端整数
-
1、 192.168.23.1
- 转成整数:192<<24|168<<16|23<<8|1<<0
- 转成大端:htonl(192<<24|168<<16|23<<8|1<<0)
-
2、
-
#include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> in_addr_t inet_addr(const char *cp); // 功能:把字符串格式的点分十进制ip地址转换成整数形式的ip地址(大端) char *inet_ntoa(struct in_addr in); // 功能:把整数形式的ip地址转换成字符串形式的点分十进制ip地址
-
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
// 功能:把4字节的本地字节序数据转换成网络字节序
uint16_t htons(uint16_t hostshort);
// 功能:把2字节的本地字节序数据转换成网络字节序
uint32_t ntohl(uint32_t netlong);
// 功能:把4字节的网络字节序数据转换成本地字节序
uint16_t ntohs(uint16_t netshort);
// 功能:把2字节的网络字节序数据转换成本地字节序
#include <sys/types.h>
#include <sys/socket.h>
int listen(int sockfd,int backlog);
// 功能:监听socket,只有数据流协议时才需要使用
// socketfd:socket描述符
// backlog:监听等待连接的排队数量,一般默认最大128
// 返回值:成功返回0,失败返回-1
int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen);
// 功能:等待连接,只有数据流协议时才需要使用
// socketfd:socket描述符
// addr:获取连接者的通信地址(socketaddr_in)
// addrlen:获取地址结构体的大小
// 返回值:连接成功时返回一个新的socket描述符,用于与连接者进行通信,每连接一个一个都会分配一个新的socket描述符,该socket描述符,是专门用于与对应的连接者进行通信,需要分配进程\线程进行通信
// 注意:如果没有人要连接过来,该函数会阻塞等待
int connect(int sockfd,const struct sockaddr *addr,socklen_t addrlen);
// 功能:连接socket,数据流使用
// sockfd:socket描述符
// addr:要连接的服务器IP地址
// addrlen:通信地址结构体字节数
// 返回值:连接成功返回0,失败返回-1
ssize_t recv(int sockfd,void *buf,size_t len,int flags);
// 功能:从socket中读取数据 TCP专用
// socketfd:建立连接后的新的socket描述符
// buf:存储数据的内存首地址
// len:存储数据内存的字节数
/* flags:一般写0即可
MSG_DONTWAIT 不阻塞
*/
// 返回值:成功接收到的字节数,-1表示出现错误,0表示断开连接
ssize_t send(int sockfd,const void *buf,size_t len,int flags);
// 功能:向socket发送数据 TCP专用
// socketfd:建立连接后的新的socket描述符
// buf:待发送数据的内存首地址
// len:要发送的数据的字节数
/* flags:一般写0即可,阻塞
MSG_DONTWAIT 不阻塞
*/
// 返回值:成功接收到的字节数,-1表示出现错误
// 注意:如果不需要额外的发送、接收功能,read\write也可以进行发送和接受
基于UDP协议的网络通信模型
服务器(接收者) | 客户端(发送者) |
---|---|
创建socket对象 | 创建socket对象 |
准备通信地址(本机ip) | 准备通信地址(服务器ip) |
绑定socket与通信地址 | … |
接收请求 | 发送请求 |
响应请求 | 接收响应 |
关闭 | 关闭 |
UDP协议专用的数据收发函数
#include <sys/types.h>
#include <sys/socket.h>
ssize_t sendto(int sockfd,const void *buf,size_t len,int flags,const struct sockaddr *dest_addr,socklen_t addrlen);
// 功能:发送数据
// sockfd:socket描述符
// buf:待发送的数据的内存首地址
// len:要发送的字节数
// flags:是否阻塞发送,一般写0阻塞即可
// dest_addr:通信目标的地址结构体指针
// addrlen:通信地址结构体字节数
// 返回值:成功返回发送的字节数,失败返回-1
ssize_t recvfrom(int sockfd,void *buf,size_t len,int flags,struct sockaddr *src_addr,socklen_t *addrlen);
// 功能:接收数据和ip地址
// sockfd:socket描述符
// buf:存储数据的内存首地址
// len:存储数据的内存字节数
// flags:是否阻塞发送,一般写0阻塞即可
// src_addr:用于存储发送者的通信地址结构体
// addrlen:接收发送者通信地址结构体的字节数
// 返回值:成功返回发送的字节数,失败返回-1
FTP文件传输协议
-
文件传输协议(File Transfer Protocol,FTP)是用于在网络上进行文件传输的一套标准协议,它工作在 OSI 模型的第七层,TCP 模型的第四层,即应用层,使用 TCP 传输而不是 UDP,客户在和服务器建立连接前要经过一个“三次握手”的过程,保证客户与服务器之间的连接是可靠的,而且是面向连接,为数据传输提供可靠保证。
-
FTP协议要用到两个TCP连接,一个是命令链路,用来在FTP客户端与服务器之间传递命令;另一个是数据链路,用来上传或下载数据。