1. 目的: 实现客户端向服务器发送数据
原理:
2. 建立两个控制台应用, 一个为服务器, 用于接收数据. 一个为客户端, 用于发送数据.
关键类与对应方法:
1)类 IPEndPoint:
1. 是抽象类 EndPoint 的实现类
2.Socket 对象的 RemoteEndPoint, LocalEndPoint 都是这个类型
3. 属性 Address: 使用 IPv4 表示的地址
4. 属性 Port: 使用 int 表示的端口
2)类 Socket:
这个类即可以用于作服务器端的开发, 又可以作客户端的开发
构造方法:
参数 AddressFamily: 指定使用 IPv4 的地址 InterNetwork
参数 SocketType: 指定使用流式传输 Stream
参数 ProtocolType: 指定协议类型 Tcp
1. 方法 Bind()E 绑定 IP 与端口, 这样就成为了服务器, 可以监听指定 IP 的特定端口
2. 方法 Listen(); 置于监听状态, 参数是最大的挂起数
3. 方法 Accept(): 接收客户端连接, 返回 Socket 对象, 这个方法会阻塞当前线程, 建议开启新线程执行些方法, 结合尾递归, 这样就可以接收多个客户端
4. 方法 Receive(): 接收客户端发送过来的消息, 以字节为单位进行操作, 此方法会阻塞当前线程, 建议开启新线程执行此方法, 结合尾递归, 就可以持续接收多条信息
5. 方法 Send(): 发送消息, 以字节为单位
3. 具体实现
其他内容不做过多解释了, 备注做的超详细, 应该只有笨笨的人才写这么多备注吧..
1. 服务器
主函数:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- namespace ServerTest
- {
- class Program
- {
- static void Main(string[] args)
- {
- // 调用构造函数, 使用 Start 方法
- ServerControl server = new ServerControl();
- server.Start();
- Console.ReadKey();
- }
- }
- }
ServerControl 类:
using System; using System.Collections.Generic; using System.Linq; using System.NET; using System.NET.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; namespace ServerTest { public class ServerControl { // 声明变量(使用 Socket 需 using System.NET.Sockets;) private Socket serverSocket; // 自定义有参构造方法(IP 地址, 流程传输方式, TCP 协议) public ServerControl() { serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); } // 创建启动方法(IPEndPoint 用于指定地址及端口初始化, 需 using System.NET;) public void Start() { // 服务器启动 // 绑定 IP 地址 (为任意 IP) 与端口(设置为 12345) serverSocket.Bind(new IPEndPoint(IPAddress.Any,12345)); serverSocket.Listen(10); Console.WriteLine("服务器启动成功"); // 开启线程: 目的实现服务器和客户端一对多连接 Thread threadAccept = new Thread(Accept); threadAccept.IsBackground = true; threadAccept.Start(); } // Accept 方法测试: 接收客户端连接 private void Accept() { // 接收客户端方法, 会挂起当前线程(.RemoteEndPoint 表示远程地址) Socket client = serverSocket.Accept(); IPEndPoint point = client.RemoteEndPoint as IPEndPoint; Console.WriteLine(point.Address + "[" + point.Port + "] 连接成功!"); // 开启一个新线程线程, 实现消息多次接收 Thread threadReceive = new Thread(Receive); threadReceive.IsBackground = true; threadReceive.Start(client); // 尾递归 Accept(); } // Receive 方法的使用测试 // 接收客户端发送过来的消息, 以字节为单位进行操作 // 该方法会阻塞当前线程, 所以适合开启新的线程使用该方法 // Accept()中将 Receive 作为线程传递对象, 所以要注意一点, 使用线程传递对象只能是 object 类型的!! private void Receive(object obj) { // 将 object 类型强行转换成 socket Socket client = obj as Socket; IPEndPoint point = client.RemoteEndPoint as IPEndPoint; // 此处的异常抛出主要针对客户端异常的问题 // 比如, 客户端关闭或者连接中断 // 程序会停留在 int msgLen = client.Receive(msg); 这段代码, 而导致无法继续往下走 try { byte[] msg = new byte[1024]; // 实际接收到字节数组长度, 该方法会阻塞当前线程, 即 (client.Receive(msg) 开始挂起) // 同时, 这里还是尾递归挂起处 int msgLen = client.Receive(msg); // 将 msg 装换成字符串 Console.WriteLine(point.Address + "[" + point.Port + "]:" + Encoding.UTF8.GetString(msg, 0, msgLen)); // 此处实现服务器自动向客户端返回一条消息 // 因为 Send 发送信息是以字节为单位发送的 // 所以下面 (Encoding.UTF8.GetString(msg,0,msgLen)+"yes.boy") 这一块是把这一部分均搞成 string // 后使用 Encoding.UTF8.GetBytes 统一转化成字节传递 // 这里呢, 已经实现服务器向客户端发送消息了, 客户端只需要 receive 一下, 格式一转就可视化了 client.Send(Encoding.UTF8.GetBytes(Encoding.UTF8.GetString(msg,0,msgLen)+"yes.boy")); // 尾递归实现多条消息的接收; 和 while 同理. Receive(client); } catch { Console.WriteLine(point.Address + "[" + point.Port + "]积极断开"); } } } }
2. 客户端:
主函数:
client.Connect("127.0.0.1",12345);
修改 IP 可实现不同计算机之间的连接.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ClientTest { class Program { static void Main(string[] args) { // 调用构造函数 ClientControl client = new ClientControl(); // 输入本机 IP 与端口号 client.Connect("127.0.0.1",12345); // 提示操作方法 Console.WriteLine("请输入发送至服务器的内容或者输入 quit 退出"); // 输入内容 string msg = Console.ReadLine(); // 非退出情况下操作方式, 使用 while 可以持续不断的接收用户输入 while(msg != "quit") { client.Send(msg); msg = Console.ReadLine(); } Console.ReadKey(); } } }
ClientControl 类:
using System; using System.Collections.Generic; using System.Linq; using System.NET.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; namespace ClientTest { public class ClientControl { // 声明变量 private Socket clientSocket; // 自定义有参构造方法((IP 地址, 流程传输方式, TCP 协议)) public ClientControl() { clientSocket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp); } // 创建通过 IP 与端口号连接的方法 public void Connect(string ip,int port) { clientSocket.Connect(ip, port); Console.WriteLine("连接服务器成功"); // 客户端接收服务器消息的线程 Thread threadReceive = new Thread(Receive); threadReceive.IsBackground = true; threadReceive.Start(); } // 用于测试服务器向客户端返回一条消息 private void Receive() { while(true) { try { // 用于接收服务器的回复信息 byte[] msg = new byte[1024]; int msgLen = clientSocket.Receive(msg); Console.WriteLine("服务器:"+Encoding.UTF8.GetString(msg,0,msgLen)); } // 异常处理方法 catch { Console.WriteLine("服务器积极拒绝!!"); // 退出 while 循环 break; } } } // Send 方法测试: 即发送消息, 以字节为单位 public void Send(string msg) { // 将字符创传化为字节数组 clientSocket.Send(Encoding.UTF8.GetBytes(msg)); } } }
4. 实现
本地连接: IP 为 127.0.0.1
远程连接: 因为我只有一台电脑, 所以用腾讯云服务器作为我的服务器, 我本地的 PC 作为客户端, 实现连接.
1. 修改客户端主程序里面的 IP 为我的腾讯云 IP
2. 使用远程桌面连接
3. 连接成功
来源: https://www.cnblogs.com/WeiMLing/p/11324133.html