# tcp-transfer-server **Repository Path**: louisyoungx/tcp-transfer-server ## Basic Information - **Project Name**: tcp-transfer-server - **Description**: 基于TCP协议,中转TCP连接到WebSocket连接 - **Primary Language**: Python - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 3 - **Forks**: 2 - **Created**: 2021-01-04 - **Last Updated**: 2024-04-10 ## Categories & Tags **Categories**: Uncategorized **Tags**: Python, TCP, WebSocket ## README # TCP_Transfer_Server ## 简介 ​ TCP Transfer Server是一个轻量级的转发服务器,用于转发原始TCP协议到WebSocket协议。 ## 架构 ![TCP Transfer Server架构](https://pic.downk.cc/item/5ff726763ffa7d37b37d154d.png) ## 项目结构 ``` TCP Transfer Server ├── Client │   ├── ReceiveClient.html │   ├── SendClient.py ├── Core │   ├── WebSocket │   │   ├── Utils.py │   │   ├── WebSocket.py │   │   ├── main.py │   │   └── manage.py │   └── core.py ├── Settings.py ├── runserver.py └── sendclient.py ``` ## 快速上手 ```bash # 克隆项目 git clone https://gitee.com/louisyoung1/tcp_-transfer_-server.git # 进入项目目录 cd tcp_-transfer_-server # 启动服务 python3 runserver.py # 启动Sender客户端 python3 sendclient.py ``` 用浏览器打开/Client目录下的ReceiveClient.html 浏览器控制台Console中显示sendclient.py中发送的内容 ## 基本原理 #### WebSocket (Receiver) ##### **1、客户端:申请协议升级** 首先,客户端发起协议升级请求。可以看到,采用的是标准的HTTP报文格式,且只支持`GET`方法。 ```java GET / HTTP/1.1 Host: localhost:8080 Origin: http://127.0.0.1:3000 Connection: Upgrade Upgrade: websocket Sec-WebSocket-Version: 13 Sec-WebSocket-Key: w4v7O6xFTi36lq3RNcgctw== ``` 重点请求首部意义如下: - `Connection: Upgrade`:表示要升级协议 - `Upgrade: websocket`:表示要升级到websocket协议。 - `Sec-WebSocket-Version: 13`:表示websocket的版本。如果服务端不支持该版本,需要返回一个`Sec-WebSocket-Version`header,里面包含服务端支持的版本号。 - `Sec-WebSocket-Key`:与后面服务端响应首部的`Sec-WebSocket-Accept`是配套的,提供基本的防护,比如恶意的连接,或者无意的连接。 > 注意,上面请求省略了部分非重点请求首部。由于是标准的HTTP请求,类似Host、Origin、Cookie等请求首部会照常发送。在握手阶段,可以通过相关请求首部进行 安全限制、权限校验等。 ##### **2、服务端:响应协议升级** 服务端返回内容如下,状态代码`101`表示协议切换。到此完成协议升级,后续的数据交互都按照新的协议来。 ```java HTTP/1.1 101 Switching Protocols Connection:Upgrade Upgrade: websocket Sec-WebSocket-Accept: Oy4NRAQ13jhfONC7bP8dTKb4PTU= ``` > 备注:每个header都以`\r\n`结尾,并且最后一行加上一个额外的空行`\r\n`。此外,服务端回应的HTTP状态码只能在握手阶段使用。过了握手阶段后,就只能采用特定的错误码。 ##### **3、Sec-WebSocket-Accept的计算** `Sec-WebSocket-Accept`根据客户端请求首部的`Sec-WebSocket-Key`计算出来。 计算公式为: 1. 将`Sec-WebSocket-Key`跟`258EAFA5-E914-47DA-95CA-C5AB0DC85B11`拼接。 2. 通过SHA1计算出摘要,并转成base64字符串。 伪代码如下: ```text >toBase64( sha1( Sec-WebSocket-Key + 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 ) ) ``` 验证下前面的返回结果: ```text const crypto = require('crypto'); const magic = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'; const secWebSocketKey = 'w4v7O6xFTi36lq3RNcgctw=='; let secWebSocketAccept = crypto.createHash('sha1') .update(secWebSocketKey + magic) .digest('base64'); console.log(secWebSocketAccept); // Oy4NRAQ13jhfONC7bP8dTKb4PTU= ``` ##### **四、数据帧格式** 客户端、服务端数据的交换,离不开数据帧格式的定义。因此,在实际讲解数据交换之前,我们先来看下WebSocket的数据帧格式。 WebSocket客户端、服务端通信的最小单位是帧(frame),由1个或多个帧组成一条完整的消息(message)。 1. 发送端:将消息切割成多个帧,并发送给服务端; 2. 接收端:接收消息帧,并将关联的帧重新组装成完整的消息; *** #### TCP Socket (Sender) ​ TCP三次握手(Three-Way Handshake)即建立TCP连接,就是指建立一个TCP连接时,需要客户端和服务端总共发送3个包以确认连接的建立。在socket编程中,这一过程由客户端执行connect来触发,整个流程如下图所示: ![TCP三次握手](https://pic.downk.cc/item/5ff72b8f3ffa7d37b3806362.png) ##### (1)第一次握手: ​ Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。 ##### (2)第二次握手: ​ Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。 ##### (3)第三次握手: ​ Client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以开始传输数据了。 ## 参与贡献 1. Fork 本仓库 2. 新建 Feat_xxx 分支 3. 提交代码 4. 新建 Pull Request ## 开源协议 [MIT](https://github.com/louisyoungx/tcp-transfer-server/blob/master/LICENSE) Copyright (c) 2021-present Louis Young