Tcp Socket 入门体验程序——Echo

上一篇《简述网络编程中的socket》阐述了socket的基本概念,从这一篇的Echo开始逐步打造一个完整的网络应用程序。

Echo是一个简单的回显程序,客户端向服务端发送消息,然后服务端将该消息完整地返回,我们在这里基于TCP协议实现该程序,代码如下:

服务端代码:

TcpServer类代码: using System; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; namespace Echo.Server { public class TcpServer { public void Start(int port) { // 创建服务端的Socket m_socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // 创建IP和端口节点对象 IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, port); // 为监听socket绑定IP和端口 m_socketServer.Bind(endPoint); // 把监听socket至于被动监听状态 m_socketServer.Listen(10); // accept函数会在此处阻塞,直到有客户端的连接请求,根据该请求的创建新的socket Console.WriteLine("开始监听,等待客户端连接..."); Socket clientSocket = m_socketServer.Accept(); Console.WriteLine("客户端已连接,开始接收数据..."); while (true) { // 初始化一个用于接收数据的字节数组 byte[] buf = new byte[1024]; // receive 会阻塞程序,直到接收到数据 int rcvLen = clientSocket.Receive(buf); string msg = Encoding.UTF8.GetString(buf.Take(rcvLen).ToArray()); Console.WriteLine(#34;来自客户端的数据:{msg}"); clientSocket.Send(buf.Take(rcvLen).ToArray()); } } private Socket m_socketServer; } } main 函数的调用代码: static void Main(string[] args) { TcpServer server = new TcpServer(); server.Start(8800); }

客户端代码:

TcpClient 类代码: using System; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; namespace Echo.Client { public class TcpClient { public Socket Connect(string ip,int port) { Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse(ip), port); s.Connect(endPoint); return s; } public void InputLoop(Socket s) { while (true) { Console.Write("等待输入:"); string msg = Console.ReadLine(); byte[] buf = Encoding.UTF8.GetBytes(msg); s.Send(buf); byte[] bufServer = new byte[1024]; int rcvlen=s.Receive(bufServer); Console.WriteLine(#34;接收到服务端的回写:{Encoding.UTF8.GetString(bufServer.Take(rcvlen).ToArray())}"); } } } } main 函数的调用代码: static void Main(string[] args) { TcpClient client = new TcpClient(); Console.Write("按任意键发起连接请求"); Console.ReadKey(); Socket s= client.Connect("127.0.0.1", 8800); Console.WriteLine("成功连接到服务端"); client.InputLoop(s); }

为了模拟服务端和客户端两个进程,分别创建了两个C#的控制台项目,Echo.Server和Echo.Client,这两个程序都在本机进行调试,具体的工作过程如下:

服务端会创建监听套接字,该套接字绑定的终结点IP地址为–IPAddress.Any,该值表示服务端会接受本机任何IP地址收到的请求;端口可以在合法值范围内任选一个,笔者选取的是8800,在同一台设备上,端口不能重用,如果出现端口重用的问题,可以换一个可用端口再次尝试。

接下来是打开被动监听,即代码中的对Listen函数的调用,其中参数值的选取不属于本篇范围,后续章节会展开说明。再往后的Accept函数会阻塞主线程,等待客户端连入,该函数结束阻塞后返回新的Socket对象,利用这个新的Socket对象可以在服务端和客户端两个端点间进行数据交互。

新的Socket对象调用接收函数Receive向系统发起IO请求,等待客户端数据,如果没有数据,该函数也会阻塞直到数据接收完成。此处,我们不知道要接收多少个字节,给定了一个固定值1024。Receive成功返回后会将接收到的数据写入到我们提供的缓存中,即代码中的字节数组buf,并且返回实际接收到的字节数rcvLen。我们给定字节数组和字符串转换的编码方式为UTF8,所以此处通过UTF8将字节数组转换为字符串输出到控制台,并且调用Send函数将接收到的字节发送回客户端,完成数据回写操作。

客户端相对来说会简单一些,首先创建Socket对象,该对象调用Connect函数向指定IP地址和端口的节点发起连接请求,在Connect未完成前该函数会一直阻塞,服务端接收连接后,该函数返回,现在就可以使用开始创建的Socket对象进行数据收发操作了。

在代码中可以看到,InputLoop函数是一个死循环,该循环开始会等待用户向控制台输入数据,输入的数据会通过UTF8的编码方式转换为字节数组,socket对象调用Send函数将该字节数组发送出去,发送完成后,调用Receive,等待服务的回写数据,Receive返回,将转换后的字符串输出到控制台,完成回写,如此循环往复。

这两个模拟程序虽然简单,却包含了TCP Socket 通信的全部流程,适合初尝网络编程的小伙伴玩味理解。

发表回复

您的邮箱地址不会被公开。必填项已用 * 标注