网络编程——TCP、UDP
1.基础知识
1.概念
不同主机的进程间通信
2.基本通信流程
ip地址 ---就是网络中身份证 ---- 用来唯一的标识一台主机
ip = 网络号 + 主机号
ip 本质 32位的数值
点分十进制
子网掩码
255.255.255.0
用来区分网络
默认网关
用于发送ip
DNS
将域名转化为用于寻址的ip地址
3.分层
osi模型 (开放的系统互联模型)
7.应用层 //
6.表示层 //加密传输的需要 --- 数据的格式化
加密解密 gzip
5.会话层 //连接状态 --长连接 ,短链接,连接的质量问题
网络断开,连接状态,keep-close keep-alive
//登录某个网站:
4.传输层 //传输控制协议
tcp udp 协议 文件 视频,音频
可靠传输 &
tcp:
下载文件,传输文件。
udp:
音频,视频,游戏开黑
3.网络层 ----- 数据包 (packet)
ip NAT
//怎么找到 对方
2.链路层 (封装成帧 + 差错控制)
交换机 (全双工,实时的工作的。)
数据的格式化 (大量数据交互时,字节为单位,字节大小端)
帧
校验
1.物理层 ----- bit流
100Mb/8 Gbits 100MB 同轴电缆
(
电气特性: 0,1高低电平特性
物理特性: 0,1规程特性: 超5类 ,超6类,远距离传输
2.tcp编程函数接口
1.socket
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
功能:
创建了通信的一端
返回文件描述符
参数:
@domain //域 -- 范围
//ip地址
// ipv4 32位数据
// ipv6 128位
//本地套接字
//protocol //协议
AF_INET
@type //用来说明socket这种网络通信的文件的类型
SOCK_STREAM //流式套接字 ---tcp
SOCK_DGRAM //数据报套接字 ---udp
@protocol //协议
0 //linux系统上 SOCK_STREAM --- TCP
//类linux系统行
// SOCK_DGRAM --- UDP
返回值:
成功 返回socket对应的fd
失败 -1 && errno被设置 //perror
注:两个重点协议
TCP(transmision control protocol):(类似 打电话)---可靠(1.连接 2.可靠传输 3.字节流)
1.特点:
a.面向连接(就是在进行通信之前,必须建立好一条逻辑上的通路)
b.提供可靠传输(四个"无",无丢失,无失序,无差错,无重复)
2.建立连接:
tcp三次握手 目的:建立连接
client ------------------ server
1 -- 我要通话 --> 1 //连接的请求
2 <--嗯,我知道了,你可以-- //对方接听电话 喂
3 -- 嗯,好的 --> //喂
3.应用场合:
(1). 对可靠性要求较高场合
(2). QQ微信等 软件的登录
UDP(User datagram Protocol):(类似 生活中的广播) (1.不可靠, 2.无连接 3.数据报)
1.特点:
不提供可靠传输,
在数据发送时,不需要建立连接
2.应用:
(1).小数据,但是对速度要求较高
(QQ.及时文本信息,语音等),实时性要求较高场合!
(2).广播,组播 //电子教师(vnc --- 广播)
(3).无线网的传输 //udp
2.connect
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
功能:
通过socket链接到指定的地址上
参数:
@sockfd --- socket创建的fd
@addr --- 标识网络中一个进程对应的地址
ip 确定一台主机
端口号 用来标识一个网络通信的进程
ip+端口号
struct sockaddr *addr//不是通用的
socket 不同的通信范围
不同通信域 都有自己特定的结构体
ipv4
struct sockaddr_in {
sa_family_t sin_family; /* address family: AF_INET */
in_port_t sin_port; /* port in network byte order */
struct in_addr sin_addr; /* internet address -- ip地址*/
}; /* Internet address. */
struct in_addr {
in_addr_t s_addr; /* address in network byte order */
};
in_addr_t inet_addr(const char *cp);
@addrlen
说明 第二个参数的 地址类型的大小
返回值:
成功 0
失败 -1&&errno端口号:
16位的整型数据0~1023 //1024 ---知名端口号
//http -- 80
1024~50000 //特定端口号
50000~ //临时分配的端口号
大小端
发送 --- 转换 --- 网络字节序 (大端)
接收 --- 根据主机的大小端转换
#include <arpa/inet.h>uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);h -- host
to -- 到
n --networkl -- long //处理4字节数据
s -- short //处理2字节数据
in_addr_t inet_addr(const char *cp);
cp 表示要用的ip地址的字符串 //点分十进制
"192.168.0.150"
返回:
网络字节序形式的ip地址的32位数值
3.bind
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
int bind (int sockfd, const struct sockaddr *addr, socklen_t addrlen);
功能:
给sockfd 绑定一个地址信息(ip+port)
参数:
@sockfd --- 要操作的socket
@addr --- 要绑定的地址信息
@addrlen --- 地址信息对应的大小
返回值:
成功 0
失败 -1&&errno
4.listen
int listen(int sockfd, int backlog);
功能:
将sockfd对应的socket设置为监听套接字
//这个套接字 负责看 有没有客户端,发送连接请求
//有了放等待队列中
参数:
@sockfd ---socket 的fd
@backlog --- 等待队列的长度
返回值:
成功 0
失败 -1&&errno
//dos 攻击
5.accept
int accept (int sockfd, struct sockaddr *addr, socklen_t *addrlen);
功能:
从监听的socket中提取连接请求,完成连接(三次握手)
返回已连接的一个新socket
参数:
@sockfd --- 监听的socket的fd
@addr --- 用来存放,客户端的地址信息
@addrlen --- 值结果参数
注意: 必须初始化 ,初始成 addr对应sockaddr_in 类型的大小
返回值:
成功 返回 已连接的socket的fd //专门用于后面通信的
失败 -1 &&errno
6.send
ssize_t read( int fd, void *buf, size_t count );
recv(sockfd,buf,sizeof(buf),0);<=>read(sockfd,buf,sizeof(buf),0);
ssize_t send(int sockfd, const void *buf, size_t len , int flags);
功能:
向socket中发送信息
参数:
@sockfd --- 要操作的socket
@buf --- 存放数据的空间
@len --- 发送的数据大小
@flags --- 操作标志
MSG_DONTWAIT
返回值:
成功 发送出去字节数
失败 -1 && errno
7.recv
ssize_t recv(int sockfd, void *buf, size_t len , int flags);
功能:
从socket中接收信息
参数:
@sockfd --- 要操作的socket
@buf --- 存放数据的空间
@len --- buf的大小
@flags --- 指定读取信息的操作标志
MSG_DONTWAIT
返回值:
成功 读取到的字节数
失败 -1 && errno
3.udp编程函数接口
1.socket
2.sendto
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
功能:
向socket中发送信息
参数:
@sockfd --- 要操作的socket
@buf --- 存放数据的空间
@len --- 发送的数据大小
@flags --- 操作标志
MSG_DONTWAIT
@dest_addr --- 要发送到的目的地址
@addrlen --- 地址大小
返回值:
成功 发送出去字节数
失败 -1 && errno
3.bind
4.recvfrom
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
功能:
从socket中接收信息
参数:
@sockfd --- 要操作的socket
@buf --- 存放数据的空间
@len --- buf的大小
@flags --- 指定读取信息的操作标志
MSG_DONTWAIT
@src_addr --- 保存 客户端的地址信息
@addrlen --- 值结果参数
注意:
使用时,需要 初始化 addrlen = sizeof(struct sockaddr_in);
返回值:
成功 读取到的字节数
失败 -1 && errno
4.交互过程
1.tcp
客户端
- socket
- connect
- recv/send
- close
服务器端
- socket
- bind
- listen
- accept
- recv/send
- close
注:交互过程中可能会出现粘包现象,是因为tcp的交互的特殊性导致的
解决方式:要让消息之间有边界
a. 结束标志 \r\n
b. 固定长度
c. 协议结构体
2.udp
客户端:主动
- socket
- sendto
- recvfrom
- close
服务器端:被动
- socket
- bind
- recvfrom
- printf
- sendto
- close