本例内容为书上1.4.4内容的改版,主要实现服务端和客户端分离。
服务端程序:
1 static void Main(string[] args) 2 { 3 int dataLength; 4 string tmpStr; 5 byte[] dataBytes1 = new byte[1024]; 6 //指定监听端口开始 7 Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); 8 IPEndPoint myHost = new IPEndPoint(IPAddress.Any, 8080); 9 //指定监听端口结束 10 EndPoint client1 = new IPEndPoint(IPAddress.Any, 8080); 11 socket.Bind(myHost); 12 while (true) 13 { 14 Console.WriteLine("等待接收..."); 15 dataLength = socket.ReceiveFrom(dataBytes1,ref client1); 16 tmpStr = System.Text.Encoding.Unicode.GetString(dataBytes1, 0, dataLength); 17 Console.WriteLine($"接收到来自{client1.ToString()}的信息:{tmpStr}"); 18 if (tmpStr == "ServerOver") break; 19 } 20 socket.Close(); 21 Console.WriteLine("对方已要求服务器退出,请按回车键结束。"); 22 Console.ReadLine(); 23 }
客户端程序:
1 static void Main(string[] args) 2 { 3 byte[] dataBytes; 4 Socket socket =new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); 5 //指定使用哪个套接字发送开始 6 IPEndPoint myHost = new IPEndPoint(IPAddress.Any, 8081); 7 socket.Bind(myHost); 8 //指定使用哪个套接字发送结束 9 //指定服务器开始 10 IPEndPoint remoteIPEnd = new IPEndPoint(IPAddress.Parse("192.168.1.105"), 8080); 11 EndPoint remoteHost = (EndPoint)remoteIPEnd; 12 //指定服务器结束 13 Console.Write("输入发送的信息:"); 14 string tmpStr = Console.ReadLine(); 15 dataBytes = System.Text.Encoding.Unicode.GetBytes(tmpStr); 16 socket.SendTo(dataBytes, dataBytes.Length, SocketFlags.None, remoteHost); 17 while (true) 18 { 19 if (tmpStr == "exit") 20 { 21 break; 22 } 23 Console.Write("输入发送信息(exit退出):"); 24 tmpStr = Console.ReadLine(); 25 dataBytes = System.Text.Encoding.Unicode.GetBytes(tmpStr); 26 socket.SendTo(dataBytes, remoteHost); 27 } 28 socket.Close(); 29 Console.WriteLine("对方已经退出了,请按回车键结束。"); 30 Console.ReadLine(); 31 }
运行效果:
不同电脑测试也通过。
基于此,就应当能很轻松完成P24页第4题了。
扩展:
都写到这里了,大家结合之前的网络知识,再思考一下,如何突破单边的源地址转换限制,实现内网和公网pc收发消息?
提示:内网机器先发出消息,利用出口转换表里的地址和端口对应关系,让服务器也可以访问到客户机。
代码修改1:发送消息程序,服务器ip和端口需要在运行时由用户指定。
代码修改2:内网机器的发送和接收,使用了相同的ip和端口。必须开启端口复用才能工作。代码为:“socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);”
效果如下图:
其中,远程桌面使用的是一台公网机器,右侧是本机。
运行顺序为图中顺序。
此时,内网机器也能够被其他内网机器连接并接收消息:
这也是qq最基本的通信原理。
思考题:如何利用一台公网服务器,构建简单聊天室?