TCP
1. 什么是 TCP?
TCP (Transmission Control Protocol) 是一个面向连接的、可靠的、字节流服务的传输层协议。它确保所有数据都将从源到目的地无错误地传输,同时也确保数据包按照其发送顺序到达。
2.TCP 的三次握手:
当 TCP 建立连接时,它会进行所谓的 "三次握手":
<img src="三次握手.png" width="500"/>
SYN: 客户端发送一个 SYN (synchronize) 数据包到服务器,请求连接。
SYN-ACK: 服务器确认客户端的 SYN 请求,并发送一个自己的 SYN 请求加上一个 ACK (acknowledge)。
ACK: 客户端再次发送一个 ACK 数据包给服务器,确认服务器的 SYN 请求。
完成这三个步骤后,连接被建立,数据传输可以开始。
3. TCP 的四次挥手:
当 TCP 连接关闭时,它会进行所谓的 "四次挥手":
<img src="四次挥手.png" width="500"/>
FIN: 主动方发送一个 FIN (finish) 数据包到被动方,表示它已完成数据发送。
ACK: 被动方接收到 FIN 数据包,并发送一个 ACK 数据包回应。
FIN: 然后,被动方也发送一个 FIN 数据包给主动方,表示它也已完成数据发送。
ACK: 主动方接收到 FIN 数据包,并再次发送一个 ACK 数据包回应。此时,连接被完全关闭。
4.OSI模型
接下来代码TCP群聊实现功能
步骤:
## Node.js 创建 TCP 服务器和客户端
在 Node.js 中提供了 net 模块提供了 TCP 编程 net 模块是 nodejs 核心模块之一
[nodejs net模块文档](https://nodejs.org/dist/latest-v18.x/docs/api/net.html)
[nodejs中文网 net模块文档](https://www.nodejs.com.cn/api/net.html)
### tcp服务端
```js
// 导入
const net = require("net");
// 创建服务端
const server = net.createServer();
// 监听端口
server.listen(9000, "127.0.0.1");
```
### tcp客户端
```js
const net = require('net');
const client = net.createConnection({port: 9000}, () => {
console.log('链接成功');
});
client.on('data', (data) => {
console.log(data.toString());
});
----
#事件监听
-----
#### net.Server 事件
1. listening
- 当服务器调用 server.listen() 后绑定端口并开始监听时,触发此事件。
```js
server.on('listening', () => {
console.log('Server is listening...');
});
2. connection:
- 当有新的连接被建立时,触发此事件。此事件的回调函数会接收到表示该连接的 socket 对象。
```js
server.on('connection', (socket) => {
console.log('New connection established');
});
3. close:
- 当服务器关闭时,触发此事件。注意,不是当单个连接关闭,而是整个服务器实例关闭时。
```js
server.on('close', () => {
console.log('Server closed');
});
4. error:
- 当服务器发生异常时,触发此事件。这是捕获和处理服务器相关错误的重要事件。
```js
server.on('error', (err) => {
console.error('Server error:', err.message);
});
net.Server -> socket 事件 **(注意: 这实际上是在 socket 对象上,不是 server 上)**
1. data:
- 当接到来自客户端的数据时,触发此事件。这通常是在与 connection 事件相关的 socket 上使用的。
```js
server.on('connection', (socket) => {
socket.on('data', (data) => {
console.log('Received data:', data.toString());
});
});
2. end:
- 当另一发送 FIN 包(表示它已完成数据发送)时,触发此事件。
```js
socket.on('end', () => {
console.log('Other end has sent a FIN packet');
});
3. close:
- 当套接字完全关闭时,触发此事件。此事件的回调可以接收一个布尔值参数,如果为 true 表示套接字是由于传输错误或其他异常而关闭的。
```js
socket.on('close', (hadError) => {
if (hadError) {
console.log('Socket closed due to an error');
} else {
console.log('Socket closed gracefully');
}
});
4. error:
- 当套接字发生错误时,触发此事件。
```js
socket.on('error', (err) => {
console.error('Socket error:', err.message);
});
5. connect:
- 当成功地建立套接字连接后,触发此事件。此事件通常在客户端套接字上更为有用,因为它表示已成功连接到服务器。
```js
socket.on('connect', () => {
console.log('Successfully connected');
});
```
6. timeout:
- 当套接字闲置超时后,触发此事件。这可以通过 socket.setTimeout() 来设置。
```js
socket.on('timeout', () => {
console.log('Socket timeout');
});
7. drain:
- 当写缓冲区变为空,可以继续写数据到套接字时,触发此事件。
```js
socket.on('drain', () => {
console.log('Write buffer is now empty');
});
代码如图所示:
const net = require('net')
const conn = net.createConnection({
port: 9000,
host: '127.0.0.1',
// host:'localhost',
})
conn.on('data', (data) => {
console.log(data.toString());
})
process.stdin.on('data', (data) => {
console.log('输入:' + data.toString());
conn.write(data.toString().trim())
})
const net = require('node:net')
const clientSocketList = [];
const server = net.createServer((clientSocket) => {
clientSocketList.push(clientSocket);
clientSocket.on('data', (data) => {
console.log(`收到数据:${data.toString()}`);
clientSocketList.forEach((item) => {
if (item !== clientSocket){
item.write('IP:' + clientSocket.remoteAddress
+ "端口:" + clientSocket.remotePort
+ '说:' + data.toString())
}
})
})
clientSocket.on('error', (err) => {
console.log(err);
})
})
server.listen(9000)