在TCP/IP协议中,“IP地址+TCP或UDP端口号”唯一标识网络通讯中的一个进程。“IP地址+端口号”就对应一个socket。欲建立连接的两个进程各自有一个socket来标识,那么这两个socket组成的socket pair就唯一标识一个连接。因此可以用Socket来描述网络连接的一对一关系。
常用的Socket类型有两种:流式Socket(SOCK_STREAM)和数据报式Socket(SOCK_DGRAM)。流式是一种面向连接的Socket,针对于面向连接的TCP服务应用;数据报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用。
套接字通讯原理示意
TCP的C/S架构
在整个通信过程中,服务器端有两个socket参与进来,但用于通信的只有conn这个socket。它是由 listener创建的。隶属于服务器端。客户端有一个socket参与进来。
net.Listen()
建立一个用于连接监听的套接字
listen.Accept()
// 阻塞监听客户端连接请求,成功用于连接,返回用于通信的socket
net.Dial()
客户端向服务端发起连接建立一个socket连接
并发的C/S模型通信
Server
Accept()函数的作用是等待客户端的链接,如果客户端没有链接,该方法会阻塞。如果有客户端链接,那么该方法返回一个Socket负责与客户端进行通信。所以,每来一个客户端,该方法就应该返回一个Socket与其通信,因此,可以使用一个死循环,将Accept()调用过程包裹起来。
需要注意,实现并发处理多个客户端数据的服务器,就需要针对每一个客户端连接,单独产生一个Socket,并创建一个单独的goroutine与之完成通信。
|
|
使用nc作为客户端向服务端发送信息
自定义客户端
客户端需要持续的向服务端发送数据,同时也要接收从服务端返回的数据。因此可将发送和接收放到不同的协程中。
- 主协程循环接收服务器回发的数据(该数据应已转换为大写),并打印至屏幕;
- 子协程循环从键盘读取用户输入数据。
- 读取键盘输入可使用
os.Stdin.Read()
。
注意事项:
- 服务端有对 exit返回的是
io.EOF
- 当服务端断开时,chan读取的信息就为0了即服务端已经退出,如果客户端不退出会一直报错
|
|