1 | @Author : Hale Lv |
Socket
socket: 套接字,通信技术就是两台联网的计算机之间交换数据的技术。
原意是插座,是计算机之间进行通信的一种约定或一种方式。 通过socket,计算机可接收、可发送数据
典型应用:web服务器和浏览器:浏览器获取用户输入的URL,向服务器发起请求,服务器分析接收到的URL,将对应的网页内容返回给浏览器,浏览器再经过解析和渲染,将文字、图片、视频元素呈现给用户
为了表示和区分已经打开的文件,Linux给每个文件分配一个ID整数,被称为:文件描述符File Descriptor如:
0: 输入文件 stdin,键盘
1: 输出文件 stdout ,显示器
网络连接也是一个文件,也有文件描述符
socket() 创建网络连接,打开一个网络文件,返回值即文件描述符。有文件描述符,即可使用普通的文件操作函数来传输数据,如:
read() :读取从远程计算机传来的数据
write():向远程计算机写入数据
Windows 系统中的socket
Windows:文件句柄
Liunx : 文件描述符
套接字的类型,socket的类型
有很多如:DARPA Internet 地址: Internet套接字、 本地节点的路径名:Unix套接字,CCITT X.25地址:X.25套接字等。
Internet 套接字:最常用、具有代表性
Internet套接字的数据传输方式:
1. 流格式套接字 SOCK_STREAM
流格式套接字:Stream Sockets 也叫"面向连接的套接字",使用SOCK_STREAM 表示
SOCK_STREAM: 是一种可靠、双向的通信流数据。可准确无误到达另一台计算机,可损坏或丢失、可重新发送
SOCK_STREAM 的特征:
1. 数据在传输过程中不会消失
2. 数据是按照顺序传输的
3. 数据的发送和接收不是同步的。也成 不存在数据边界
使用TCP协议 The Transmission Control Protocol,传输控制协议,TCP控制数据按照顺序到达并且没有错误
IP Internet Protocol 网络协议,控制数据如何从源头到达目的地,即路由
2. 数据报格式套接字 SOCK_DGRAM
数据报格式套接字 Datagram Sockets 也叫 无连接的套接字,使用SOCK_DGRAM表示
只管传输数据,不做数据校验,如损坏或丢失,不补救,无法重传。
SOCK_DGRAM 的特征:
1. 强调快速传输而非传输顺序
2. 传输的数据肯跟丢失或损坏
3. 限制每次传输的数据大小
4. 数据的发送和接收是同步的,存在数据边界
SCOK_DGRAM:是一种不可靠、不按传序传递的、以追求速度为目的的套接字
使用UDP协议 User Datagram Protocol 用户数据报协议
面向连接和无连接的套接字
流格式套接字Stream Sockets: 面向连接的套接字,基于TCP协议
数据报格式套接字 Datagram Sockets: 无连接的套接字,基于UDP协议
无连接的套接字
每个数据包可选择不同的路径
每个数据包之间是独立的
面向连接的套接字
路径是由路由器维护的,所有路由器都要存储该路径的信息
优缺点:
无连接套接字传输效率高,不可靠、丢失数据报、捣乱数据
有连接套接字可靠、传输效率低,耗费资源
有连接的套接字TCP:HTTP、FTP等
无连接的套接字UDP:DNS、即时聊天工具等
OSI 网络七层模型
OSI模型:Open System Interconnection: 开发式系统互联
七层:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层
TCP/Ip 模型: 网络接口层、网络层、传输层、应用层
网络接口:针对不同物理网络的连接形式的协议,如:Ethernet、FDDI、ATM
网络层:负责数据的传输,路径及地址选择,常用协议:IP ARP(地址解析协议)
传输层:确认数据传输及进行纠错处理,常用协议:TCP、UDP(用户数据报协议)
应用层:各种服务及应用程序通过该层利用网络,常用协议:HTTP、FTP、SMTP(简单邮件传输协议)等
发送数据包时,程序或软件是通过应用层访问网络,产生的数据会一层一层往下传输,到最后的王略接口层,通过网线发送到网上,每传一层,协议增加一层包装,比原始数据多了四层包装。
接收数据包时:从网络接口层一层一层网上传,每传一层就拆开一层包装,到最后的应用层,最原始的数据。
socket:在传输层的基础上,使用TCP/IP协议,不能访问网页,访问网页需要HTTP协议
计算机通信的原则:
1. 同一层次进行通信,
2. 功能必须相同
3. 数据只能逐层传输,不能跃层
4. 可使用下层提供的服务,并向上层提供服务
TCP/IP协议族
协议: Protocol 是网络通信过程中的约定或合同,双方必须都遵守才能正常收发数据。 协议是一种规范,通信双方需使用同一协议才能通信,
TCP/IP模型包含 TCP、IP、UDP、Telnet、FTP、SMTP等
TCP/UDP:
开放式系统 Open System
以多个标准为依据设计的系统称为开放式系统
IP、MAC和端口号 - 网络通信中确认身份信息的三要素
IP地址
是 Internet Protocol Address ,网际协议地址
Mac地址
是 Media Access Control Address , 媒体访问控制地址,称为局域网地址LAN Address,以太网地址 Ethernet Address 或 物理地址Physical Address
端口号
Port Number 为每个网路程序分配一个独一无二的端口号
是一个虚拟的、逻辑上的概念
Linux 下的Socket 演示程序
服务器端代码server.cpp:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
...
int main() {
int serv_sock = socket(AF_INET,SOCK_STREAM,IPPROPT_TCP);
struct sockaddr_in serv_addr;
}
...
[SOCKET CPP](http://c.biancheng.net/view/2128.html)
WSAStartup() 函数以及DLL的加载
[More](http://c.biancheng.net/view/2130.html)
Socket() 函数用法:创建套接字
Linux 下的Socket函数
使用<sys/socket.h> 头文件中socket函数创建套接字,原型为:
int socket(int af, int type, int protocol);
1. af: 地址族 Address Family, IP地址类型,常用AF_INET:表示IPv4地址 和 AF_INET6:表示IPv6地址,
2. type 为数据传输方式/套接字类型,常用: SOCK_STREAM 流格式套接字/面向连接套接字 和 SOCK_DGRAM 数据套接字/无连接的套接字
3. protocol 表示传输协议,常用: IPPROTO_TCP 和 IPPROTO_UDP
TCP:
int tcp_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
UDP:
int udp_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
将 protocol的值设为0, 系统可自动推演出使用的协议:
int tcp_socket = socekt(AF_INET, SOCK_STREAM, 0) // TCP
int udp_socket = socket(AF_INET, SOCK_DGRAM, 0) // UDP
bind() 和 connect()函数:绑定套接字并建立连接
使用 bind函数将套接字与特定的IP地址和端口绑定起来,
bind 函数原型:
int bind(int sock, struct sockaddr * addr, socklen_t addrlen); //linux
int bind(SOCKET sock, const struct sockaddr * addr, int addrlen); // windows
[More](http://c.biancheng.net/view/2344.html)
listen accept : 让套接字进入监听状态并响应客户端请求
listen 函数:让套接字进入被监听状态,原型:
int listen(int sock, int backlog); //linux
int listen(SOCKET sock, int backlog); // windows
sock: 进入监听状态的套接字, backlog: 请求队列的最大长度
[More](http://c.biancheng.net/view/2345.html)
send()/recv()和write()/read(): 发送数据和接收数据
Linux 下数据的接收和发送
[More](http://c.biancheng.net/view/2346.html)
1 | @Author : Hale Lv |
图解TCP数据报结构以及三次握手
TCP: Transmission Control Protocol,传输控制协议。 一种面向连接的、可靠的、基于字节流的通信协议,数据在传输前要建立连接,完毕后要断开连接
客户端在收发数据前要使用connect 函数和服务器建立连接,建立连接的目的是保证IP地址、端口、物理链路等正确无误,为数据的传输开辟通道
TCP建立连接时要传输三个数据包,俗称:三次握手 Three-way Handshaking :
[Shake 1]套接字A: "你好,套接字B,我这里有数据包传给你,建立连接吧"
[Shake 2]套接字B:"好的,这边已经准备就绪"
[Shake 3]套接字C:"谢谢你受理我的请求"
TCP三次握手:
图片中带阴影的字段说明:
1. 序号: Seq: Sequence Number : 序号占32位,用来识别从计算机A发送到计算机B的数据包的序号,计算机发送数据时对此进行标记
2. 确认号:Ack:Acknowledge Number: 确认号占32位, 客户端和服务器端都可以发送, Ack=Seq+1
3. 标志位: 每个标志位占用1Bit, 共有6个,分别为:URG、ACK、PSH、RST、SYN、FIN,具体含义:
URG: 紧急指针urgent pointer 有效
ACK: 确认序号有效
PSH: 接收方应该尽快将这个报文交给应用层
RST: 重置连接
SYN: 建立一个连接
FIN: 断开一个连接
Seq 是 Sequence 的缩写,表示序列; Ack 是 Acknowledeg 缩写,表示确认; SYN 是 Synchronous 的缩写, 愿意是 同步的, 表示建立同步连接; FIN是Finish的缩写,表示完成
连接的建立(三次握手)
使用Connect 建立连接
Three-hand: 
客户端调用socket 函数创建套接字后,因没建立连接,所以套接字处于CLOSED状态,服务器调用listen函数后,套接字进入LISTEN状态,开始监听客户端请求
客户端开始发起请求:
1. 当客户端调用connect 函数后,TCP协议会组建一个数据包,并设置SYN标志位,表示该数据包用来建立同步连接的,同时生成一个随机数字1000, 填充 序号Seq 字段,表示该数据包的序号。完成这些工作,开始想服务器端发送数据包,客户端进入SYN-SEND状态
2. 服务器端收到数据包,检测到已经设置了SYN标志位, 检测到是客户端发来的建立连接的请求包,服务器也组建一个数据包, 并设置SYN和ACK标志位,SYN表示该数据包用来建立连接,ACK用来确认收到刚才客户端发送的数据包
服务器生成一个随机数2000,填充 序号 Seq 字段,2000 和客户端数据包没有关系
服务器将数据包发出,进入SYN-RECV状态
3. 客户端收到数据包,检测到已经设置 SYN 和ACK 标志位, 检测到服务器发来的 确认包, 客户端检测 确认号 Ack 字段,看值是否为1000+1,如是说明连接成功
客户端将数据包发出,进入ESTABLISED状态,表示连接已经成功建立
4. 服务器端收到数据包,检测到已经设置ACk标志位,知道是客户端发来的 确认包,服务器会检测 确认号Ack字段, 看值是否为2000+1,如是说明连接建立成功,服务器进入ESTABLISED状态
至此,客户端和服务器都进入ESTABLISED状态,连接建立成功,接下可收发数据
最后的说明:
三次握手的关键是要确认对方收到了自己的数据包,目标就是通过 确认号 Ack 字段实现的,计算机会记录下自己发送的数据包序号Seq,待收到对方的数据包后,检测 确认号Ack字段,看Ack = Seq + 1 是否成立, 如成立说明对方正确收到了自己的数据包
TCP数据的传输过程
Ack 号 = Seq号 + 传递的字节数 + 1
重传超时事件 RTO , Retransmission Time Out
重传次数
TCP四次握手断开连接
[More](http://c.biancheng.net/view/2353.html)
shotdown 函数: 优雅地断开TCP连接
[More](http://c.biancheng.net/view/2354.html)
Socket 实现文件传输
Client 从Server 下载一个文件并保存到本地
需注意:
1. 文件大小不确定该,调用一次write /send 函数不能完成文件内容的发送,接收数据也同样
解决方案: 可使用while 循环:
int nCount;
while(nCount = fread(buffer, 1, BUF_SIZE, fp)) > 0 {
send(sock, buffer, nCount, 0);
}
// Client
int nCount;
while((nCount = recv(clntSock, buffer, BUF_SIZE, 0)) > 0 ) {
fwrite(buffer, nCount, 1, fp);
}
[More](http://c.biancheng.net/view/2355.html)
网络数据的大小端问题
大端序和小端序
网络字节序转换函数
gethostbyname: 通过域名获取IP地址
通过域名获取IP地址
[More](http://c.biancheng.net/view/2359.html)