1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152## 应用构建
### 创建TCP服务端
下面是一个在NodeJS中创建TCP服务端套接字的简单例子,相关说明见代码注释。
```js
var net = require('net');
var HOST = '127.0.0.1';
var PORT = 6969;
// 创建一个TCP服务器实例,调用listen函数开始监听指定端口
// 传入net.createServer()的回调函数将作为”connection“事件的处理函数
// 在每一个“connection”事件中,该回调函数接收到的socket对象是唯一的
var server = net.createServer();
server.listen(PORT, HOST);
console.log('Server listening on ' +
server.address().address + ':' + server.address().port);
server.on('connection', function(sock) {
console.log('CONNECTED: ' +
sock.remoteAddress +':'+ sock.remotePort);
});
```
首先我们来看下 `net.createServer`, 它返回一个 `Server`的实例,如下。
```js
1075 function Server(options, connectionListener) {
1076 if (!(this instanceof Server))
1077 return new Server(options, connectionListener);
1078
1079 EventEmitter.call(this);
1080
1081 var self = this;
1082
1083 if (typeof options === 'function') {
1084 connectionListener = options;
1085 options = {};
1086 self.on('connection', connectionListener);
1087 } else {
1088 options = options || {};
1089
1090 if (typeof connectionListener === 'function') {
1091 self.on('connection', connectionListener);
1092 }
1093 }
1094
1095 this._connections = 0;
1096 // ...
1111
1112 this._handle = null;
1113 this._usingSlaves = false;
1114 this._slaves = [];
1115 this._unref = false;
1116
1117 this.allowHalfOpen = options.allowHalfOpen || false;
1118 this.pauseOnConnect = !!options.pauseOnConnect;
1119 }
1120 util.inherits(Server, EventEmitter);
```
`Server` 继承了 `EventEmitter`, 如果传入 callback 函数, L1086,L1091 则把传入的函数作为监听者
绑定到 `connnection`事件上, 然后 listen 。我们看看作为 server 端连接到来的回调处理。
```js
1400 function onconnection(err, clientHandle) {
1401 var handle = this;
1402 var self = handle.owner;
1403
1404 debug('onconnection');
1405
1406 if (err) {
1407 self.emit('error', errnoException(err, 'accept'));
1408 return;
1409 }
1410
1411 if (self.maxConnections && self._connections >= self.maxConnections) {
1412 clientHandle.close();
1413 return;
1414 }
1415
1416 var socket = new Socket({
1417 handle: clientHandle,
1418 allowHalfOpen: self.allowHalfOpen,
1419 pauseOnCreate: self.pauseOnConnect
1420 });
1421 socket.readable = socket.writable = true;
1422
1423
1424 self._connections++;
1425 socket.server = self;
1426 socket._server = self;
1427 // ...
1431 self.emit('connection', socket);
1432 }
```
此函数由 `TCPWrap::OnConnection`回调,`tcp_wrap->MakeCallback(env->onconnection_string(), ARRAY_SIZE(argv), argv);`, 第一个参数标识状态,第二个参数为连接的句柄。
L1416-L1421, 根据传过来的句柄,创建 JS 层面的 Socket。并在 L1431 向观察者发送 connection 事件。
上面 TCP 服务端的例子,server 监听connection 事件,自定义用户处理逻辑。
### 创建TCP客户端
现在让我们创建一个TCP客户端连接到刚创建的服务器上,该客户端向服务器发送一串消息,并在得到服务器的反馈后关闭连接。下面的代码描述了这一过程。
```js
var net = require('net');
var HOST = '127.0.0.1';
var PORT = 6969;
var client = new net.Socket();
client.connect(PORT, HOST, function() {
console.log('CONNECTED TO: ' + HOST + ':' + PORT);
// 建立连接后立即向服务器发送数据,服务器将收到这些数据
client.write('I am Chuck Norris!');
});
// 为客户端添加“data”事件处理函数
// data是服务器发回的数据
client.on('data', function(data) {
console.log('DATA: ' + data);
// 完全关闭连接
client.destroy();
});
// 为客户端添加“close”事件处理函数
client.on('close', function() {
console.log('Connection closed');
});
```
创建 `Socket`对象后,client 端向server端发起连接,在真正的连接之前,需要进行 DNS 查询(提供 IP 的不用),
调用 `lookupAndConnect`, 之后才是调用 `function connect(self, address, port, addressType, localAddress, localPort) `发起连接。
我们注意到五元组: `<remoteAddress, remotePort, addressType, localAddress, localPort>`, 他们唯一的标识了一个网络连接。
建立起全双工的 Socket 后,用户程序就可以监听 「data」事件,获取数据了。
### 总结
### 参考