winform客户端、服务器异步通信

winform客户端、服务器异步通信 视频演示

主要代码

#要发送的数据主体class PersonPackage{public bool IsMale { get; set; }public ushort Age { get; set; }public string Name { get; set; }public PersonPackage(bool male, ushort age, string name){IsMale = male;Age = age;Name = name;}/// <summary>/// 反序列化接收到的字节数组 /// </summary>public PersonPackage(byte[] data){//字节数组data 反序列化为 性别bool ,年龄uint16,名称长度int32。共需要1+2+4=7字节。data后面的是名字   IsMale = BitConverter.ToBoolean(data, 0);Age = BitConverter.ToUInt16(data, 1);int nameLength = BitConverter.ToInt32(data, 3);Name = Encoding.ASCII.GetString(data, 7, nameLength);}/// <summary>///  将此人信息序列化为字节数组。/// </summary>/// <remarks>/// Use the <see cref="Buffer"/> or <see cref="Array"/> class for better performance./// </remarks>public byte[] ToByteArray(){List<byte> byteList = new List<byte>();//字节列表byteList.AddRange(BitConverter.GetBytes(IsMale));//bool->字节byteList.AddRange(BitConverter.GetBytes(Age));//ushort / uint16->字节byteList.AddRange(BitConverter.GetBytes(Name.Length));//int32->字节byteList.AddRange(Encoding.ASCII.GetBytes(Name));//string->字节return byteList.ToArray();//字节列表->字节数组}}
#客户端窗体类代码public partial class ClientForm : Form{private Socket clientSocket;private byte[] buffer;public ClientForm(){InitializeComponent();}//显示错误对话框private static void ShowErrorDialog(string message){MessageBox.Show(message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);}//接收回调private void ReceiveCallback(IAsyncResult AR){try{int received = clientSocket.EndReceive(AR);if (received == 0){return;}string message = Encoding.ASCII.GetString(buffer);Invoke((Action) delegate{Text = "Server says: " + message;});// 再次开始接收数据。clientSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallback, null);}//在这种情况下避免 Pokemon 异常处理。catch (SocketException ex){ShowErrorDialog(ex.Message);}catch (ObjectDisposedException ex){ShowErrorDialog(ex.Message);}}//连接服务器回调private void ConnectCallback(IAsyncResult AR){try{clientSocket.EndConnect(AR);//结束挂起的异步连接请求。UpdateControlStates(true);//发送按钮可用,连接按钮不可用,label不可见buffer = new byte[clientSocket.ReceiveBufferSize];clientSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallback, null);}catch (SocketException ex){ShowErrorDialog(ex.Message);}catch (ObjectDisposedException ex){ShowErrorDialog(ex.Message);}}//发送字节数组给服务器的回调函数private void SendCallback(IAsyncResult AR){try{clientSocket.EndSend(AR);//结束挂起的异步发送}catch (SocketException ex){ShowErrorDialog(ex.Message);}catch (ObjectDisposedException ex){ShowErrorDialog(ex.Message);}}/// <summary>/// 启用发送按钮的线程安全方式。/// </summary>private void UpdateControlStates(bool toggle)//toggle==fasle时{Invoke((Action)delegate{buttonSend.Enabled = toggle;//发送按钮不可用buttonConnect.Enabled = !toggle;//连接按钮可用labelIP.Visible = textBoxAddress.Visible = !toggle;//label可见});}//发送人的信息 字节数据private void buttonSend_Click(object sender, EventArgs e){try{// 在发送之前序列化 textBoxes 文本。PersonPackage person = new PersonPackage(checkBoxMale.Checked, (ushort)numberBoxAge.Value, textBoxEmployee.Text);byte[] buffer = person.ToByteArray();//序列化为字节数组clientSocket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, SendCallback, null);//发送字节数组给服务器}catch (SocketException ex)//主机断开后,再次发送引发异常{ShowErrorDialog(ex.Message);UpdateControlStates(false);//IP可见}catch (ObjectDisposedException ex){ShowErrorDialog(ex.Message);UpdateControlStates(false);}}//连接服务器private void buttonConnect_Click(object sender, EventArgs e){try{//使用指定的地址族、套接字类型和协议初始化 System.Net.Sockets.Socket 类的新实例clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//连接到指定的主机。var endPoint = new IPEndPoint(IPAddress.Parse(textBoxAddress.Text), 3333);clientSocket.BeginConnect(endPoint, ConnectCallback, null);//开始一个对远程主机连接的异步请求}catch (SocketException ex)//发生套接字错误时引发的异常。{ShowErrorDialog(ex.Message);}catch (ObjectDisposedException ex)//对已释放的对象执行操作时所引发的异常。{ShowErrorDialog(ex.Message);}}}
#服务器端窗体类代码public partial class ServerForm : Form{private Socket serverSocket;  //服务端套接字private Socket clientSocket; // 我们将只接收一个客户端private byte[] buffer;//接收缓存public ServerForm(){InitializeComponent();StartServer();}//显示错误对话框private static void ShowErrorDialog(string message){MessageBox.Show(message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);}/// <summary>/// Construct server socket and bind socket to all local network interfaces, then listen for connections/// with a backlog of 10. Which means there can only be 10 pending connections lined up in the TCP stack/// at a time. This does not mean the server can handle only 10 connections. The we begin accepting connections./// Meaning if there are connections queued, then we should process them./// 构造服务器套接字并将套接字绑定到所有本地网络接口,然后侦听积压为 10 的连接。这意味着 TCP 堆栈中一次只能有 10 个未决连接排队。/// 这并不意味着服务器只能处理 10 个连接。我们开始接受连接。这意味着如果有连接排队,那么我们应该处理它们。/// </summary>private void StartServer(){try{serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);serverSocket.Bind(new IPEndPoint(IPAddress.Any, 3333));serverSocket.Listen(10);//将 System.Net.Sockets.Socket 置于侦听状态。serverSocket.BeginAccept(AcceptCallback, null);//开始一个异步操作来接受一个传入的连接尝试。}catch (SocketException ex){ShowErrorDialog(ex.Message);}catch (ObjectDisposedException ex){ShowErrorDialog(ex.Message);}}private void AcceptCallback(IAsyncResult AR){try{clientSocket = serverSocket.EndAccept(AR);// 异步接受传入的连接尝试,并创建新的 System.Net.Sockets.Socket 来处理远程主机通信。buffer = new byte[clientSocket.ReceiveBufferSize];// 向新连接的客户端发送消息。var sendData = Encoding.ASCII.GetBytes("Hello");clientSocket.BeginSend(sendData, 0, sendData.Length, SocketFlags.None, SendCallback, null);// 监听客户端数据。clientSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallback, null);// 继续倾听客户。serverSocket.BeginAccept(AcceptCallback, null);}catch (SocketException ex){ShowErrorDialog(ex.Message);}catch (ObjectDisposedException ex){ShowErrorDialog(ex.Message);}}//发送回调private void SendCallback(IAsyncResult AR){try{clientSocket.EndSend(AR);}catch (SocketException ex){ShowErrorDialog(ex.Message);}catch (ObjectDisposedException ex){ShowErrorDialog(ex.Message);}}//接收回调private void ReceiveCallback(IAsyncResult AR){try{// Socket exception will raise here when client closes, as this sample does not// demonstrate graceful disconnects for the sake of simplicity.//当客户端关闭时,此处会引发套接字异常,因为为了简单起见,此示例没有演示优雅的断开连接。int received = clientSocket.EndReceive(AR);if (received == 0){return;}// 接收到的数据在 PersonPackage ctor 中反序列化。PersonPackage person = new PersonPackage(buffer);SubmitPersonToDataGrid(person);//再次开始接收数据。clientSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallback, null);}// 在这种情况下避免 Pokemon 异常处理。catch (SocketException ex){ShowErrorDialog(ex.Message);}catch (ObjectDisposedException ex){ShowErrorDialog(ex.Message);}}/// <summary>/// 提供一种线程安全的方式将行添加到datagrid。/// </summary>private void SubmitPersonToDataGrid(PersonPackage person){Invoke((Action)delegate{dataGridView.Rows.Add(person.Name, person.Age, person.IsMale);});}}


多客户端 异步通信

多客户端 异步通信   视频演示

主要代码

#多客户端实例-客户端代码class Program{private static readonly Socket ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //客户端套接字private const int PORT = 100;static void Main(){Console.Title = "Client";ConnectToServer(); //连接服务器RequestLoop();//请求循环Exit();//退出}private static void ConnectToServer()//{int attempts = 0;//尝试连接次数while (!ClientSocket.Connected)//未连接{try{attempts++;//尝试连接次数++Console.WriteLine("Connection attempt " + attempts);// 将 IPAddress.Loopback 更改为远程 IP 以连接到远程主机。ClientSocket.Connect(IPAddress.Loopback, PORT);}catch (SocketException) {Console.Clear();}}Console.Clear();Console.WriteLine("Connected");//连接成功}private static void RequestLoop(){Console.WriteLine(@"<Type ""exit"" to properly disconnect client>");while (true){SendRequest();  //发送请求ReceiveResponse();//接收响应}}/// <summary>///关闭套接字并退出程序。/// </summary>private static void Exit(){SendString("exit"); // 告诉服务器我们正在退出ClientSocket.Shutdown(SocketShutdown.Both);//禁用客户端套接字上的接收与发送ClientSocket.Close();//关闭客户端套接字Environment.Exit(0);//关闭程序}private static void SendRequest(){Console.Write("Send a request: ");string request = Console.ReadLine();//输入要发送的请求内容SendString(request);if (request.ToLower() == "exit")//如果要发送给服务器的字符串是 exit 命令{Exit();//退出}}/// <summary>/// 使用 ASCII 编码向服务器发送一个字符串。/// </summary>private static void SendString(string text){byte[] buffer = Encoding.ASCII.GetBytes(text);ClientSocket.Send(buffer, 0, buffer.Length, SocketFlags.None);}private static void ReceiveResponse() {var buffer = new byte[2048];//接收缓存int received = ClientSocket.Receive(buffer, SocketFlags.None);//接收服务器响应if (received == 0) return;var data = new byte[received];Array.Copy(buffer, data, received);//去除空字符string text = Encoding.ASCII.GetString(data);Console.WriteLine(text);//显示接收的响应文本}}
#多客户端实例-服务器端代码class Program{private static readonly Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);private static readonly List<Socket> clientSockets = new List<Socket>();  //介入的客户端套接字列表private const int BUFFER_SIZE = 2048;private const int PORT = 100;private static readonly byte[] buffer = new byte[BUFFER_SIZE];static void Main(){Console.Title = "Server";SetupServer();//设置服务器套接字 开始侦听Console.ReadLine(); //当我们按下回车关闭一切CloseAllSockets();}private static void SetupServer(){Console.WriteLine("Setting up server...");serverSocket.Bind(new IPEndPoint(IPAddress.Any, PORT));serverSocket.Listen(0);serverSocket.BeginAccept(AcceptCallback, null);//开启异步操作来接受一个传入的连接尝试Console.WriteLine("Server setup complete");}/// <summary>/// Close all connected client (we do not need to shutdown the server socket as its connections/// are already closed with the clients)./// 关闭所有连接的客户端(我们不需要关闭服务器套接字,因为它的连接已经与客户端 关闭)。/// </summary>private static void CloseAllSockets(){foreach (Socket socket in clientSockets){socket.Shutdown(SocketShutdown.Both);socket.Close();}serverSocket.Close();}private static void AcceptCallback(IAsyncResult AR){Socket socket;try{socket = serverSocket.EndAccept(AR);}catch (ObjectDisposedException) //我似乎无法避免这种情况(在正确关闭套接字时退出){return;}clientSockets.Add(socket);socket.BeginReceive(buffer, 0, BUFFER_SIZE, SocketFlags.None, ReceiveCallback, socket);//开始异步接收数据Console.WriteLine("Client connected, waiting for request...");serverSocket.BeginAccept(AcceptCallback, null);}private static void ReceiveCallback(IAsyncResult AR){Socket current = (Socket)AR.AsyncState;int received;try{received = current.EndReceive(AR);//结束挂起的异步读取}catch (SocketException){Console.WriteLine("客户端强行断开");current.Close(); //关闭该套接字clientSockets.Remove(current);//从套接字列表移除return;}byte[] recBuf = new byte[received];Array.Copy(buffer, recBuf, received);//去除空格string text = Encoding.ASCII.GetString(recBuf);Console.WriteLine("Received Text: " + text);if (text.ToLower() == "get time") // 客户端请求时间{Console.WriteLine("Text is a get time request");byte[] data = Encoding.ASCII.GetBytes(DateTime.Now.ToLongTimeString());current.Send(data);//发送时间给客户端Console.WriteLine("Time sent to client");}else if (text.ToLower() == "exit") // 客户端想要优雅地退出 {// 关闭前总是关机current.Shutdown(SocketShutdown.Both);//禁用current套接字的发送和接收current.Close();//关闭current套接字clientSockets.Remove(current);//列表中移除套接字Console.WriteLine("Client disconnected");return;}else{Console.WriteLine("Text is an invalid request");byte[] data = Encoding.ASCII.GetBytes("Invalid request");//无效请求current.Send(data);Console.WriteLine("Warning Sent");}current.BeginReceive(buffer, 0, BUFFER_SIZE, SocketFlags.None, ReceiveCallback, current);//继续从客户端套接字异步接收数据}}


同步socket通信

#主程序class Program{public const int Port = 3333;static void Main(string[] args){if (args.Length == 0){Console.WriteLine("No arguments provided.");Console.ReadLine();return;}// 参数 "/c" 将以客户端模式启动该程序。// 参数“/s”将以服务器模式启动该程序。switch (args[0].ToLower()){case "/c": Client client=  new Client();client.StartSendLoop();break;case "/s":// 也以客户端模式启动此应用程序。string fileName = System.Reflection.Assembly.GetExecutingAssembly().Location;System.Diagnostics.Process.Start(fileName, "/c");Server server = new Server();server.Start();break;}}}
/// <summary>/// 表示客户端应用程序。/// </summary>class Client{private Socket clientSocket; //客户端套接字public void StartSendLoop(){try{clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);// 将 IPAddress.Loopback 更改为远程 IP 以连接到远程主机。clientSocket.Connect(IPAddress.Loopback, Program.Port);while (true){Console.Write("Enter text to send: ");string input = Console.ReadLine();if (input == "exit"){clientSocket.Close(); //关闭客户端套接字Environment.Exit(0); //退出程序}clientSocket.Send(Encoding.ASCII.GetBytes(input));Console.Clear();}}catch (Exception ex){Console.WriteLine(ex.Message);Console.ReadLine();}}}
#服务器类class Server{private Socket serverSocket, clientSocket;private byte[] buffer;public void Start(){// Create server socket and listen on any local interface.serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);serverSocket.Bind(new IPEndPoint(IPAddress.Any, 3333));serverSocket.Listen(0);//服务端套接字处于监听状态// 后跟...表示工作中Console.WriteLine("Listening for connections on port " + Program.Port + "...");clientSocket = serverSocket.Accept(); //阻塞,等待客户端连接Console.WriteLine("Client Connected");Console.WriteLine("Waiting for data...");buffer = new byte[clientSocket.ReceiveBufferSize];ReceiveData();Console.WriteLine("Server loop ended. Press enter to exit.");Console.ReadLine();serverSocket.Close();}private void ReceiveData(){while (clientSocket.Connected){int received = clientSocket.Receive(buffer);//接收数据写入缓存if (received == 0) //假设客户端已断开连接。{Console.WriteLine("Client Disconnected");break;}// 缩小缓冲区,这样我们就不会在文本中得到空字符。Array.Resize(ref buffer, received);string receivedMsg = Encoding.ASCII.GetString(buffer);//重置缓冲区。Array.Resize(ref buffer, clientSocket.ReceiveBufferSize);Console.WriteLine("Message received: " + receivedMsg);}//假设客户端已断开连接并再次开始侦听连接。Console.WriteLine("\nListening again...");clientSocket = serverSocket.Accept();Console.WriteLine("Client Connected");Console.WriteLine("Waiting for data...");ReceiveData();}}

结语:

以上实例仅用于对网络编程概念的理解。工程上一般会使用第三方成熟的通信库。有开发通信库能力的除外。   在专业领域同样也存在这样一个问题,在学校里学了很多理论也做出过很多demo,用到工程上会发现各种问题.做工程和做学术研究最大的区别在于工程上使用的技术要求成熟、稳定、可靠。学术研究的demo可能成功了一次,失败了99次,就可以算作好的研究成果了,这些都是在非常理想的情况下做出的成果。但是在工程上你就是成功99次,有一次失败都不行,工程上有很多现实问题要面对。所以学术上的研究成果要进行工程化是有很长的路要走的。

The End

【C#-socket】网络通信实例(异步通信、多客户端异步通信、同步通信)相关推荐

  1. android socket通信如何抓取,安卓Socket通信实例(客户端、服务端)

    安卓Socket通信实例 本文摘自:https://whatsblog.icu/index.php/Android/17.html 1.Socket通信必须知道的地方 1.首先,Socket通信采用T ...

  2. Java刷题知识点之TCP、UDP、TCP和UDP的区别、socket、TCP编程的客户端一般步骤、TCP编程的服务器端一般步骤、UDP编程的客户端一般步骤、UDP编程的服务器端一般步骤...

    TCP和UDP是两个传输层协议,广泛应用于网络中不同主机之间传输数据.对任何程序员来说,熟悉TCP和UDP的工作方式都是至关重要的.这就是为什么TCP和UDP是一个流行的Java编程面试问题. Jav ...

  3. 计算机网络:Socket网络通信底层数据传输

    1. 前言 最近在研究RDMA的实时流处理系统,其中需要比较RDMA高速网络通信和传统Socket网络通信的传输特点进行比较.所以我们就来总结游戏传统Scoket网络通信的特点,对于一个程序开发人员来 ...

  4. 循序渐进Java Socket网络编程(多客户端、信息共享、文件传输)

    目录[-] 一.TCP/IP协议 二.TCP与UDP 三.Socket是什么 四.Java中的Socket 五.基本的Client/Server程序 六.多客户端连接服务器 七.信息共享 八.文件传输 ...

  5. jsd 多线程与socket网络通信

    多线程与socket网络通信 一.多线程 什么是多线程? 百度:"多线程(英语:multithreading),是指从软件或者硬件上实现多个线程并发执行的技术.具有多线程能力的计算机因有硬件 ...

  6. 笔记2:VC++ socket通信实例

    VC++ socket通信实例 网络中进程之间如何通信   首要解决的问题是如何唯一标识一个进程,在本地可以通过进程PID来唯一标识一个进程,但是在网络中这是行不通的.其实TCP/IP协议族已经帮我们 ...

  7. JAVA socket编程实例 转载

    事实上网络编程简单的理解就是两台计算机相互通讯数据而已.对于程序员而言,去掌握一种编程接口并使用一种编程模型相对就会显得简单的多了.Java SDK提供一些相对简单的Api来完成这些工作.Socket ...

  8. java socket发送定长报文_一个基于TCP协议的Socket通信实例

    原标题:一个基于TCP协议的Socket通信实例 1. 前言 一般接口对接多以http/https或webservice的方式,socket方式的对接比较少并且会有一些难度.正好前段时间完成了一个so ...

  9. JAVA socket编程实例

    2019独角兽企业重金招聘Python工程师标准>>> 事实上网络编程简单的理解就是两台计算机相互通讯数据而已.对于程序员而言,去掌握一种编程接口并使用一种编程模型相对就会显得简单的 ...

最新文章

  1. 为什么我们总认为开源不挣钱?
  2. linux中mysql回滚重演_DM7 达梦 数据库 数据守护(Data Watch) (1) -- 基本概念
  3. 利用python发送邮件_利用python实现简单的邮件发送客户端示例
  4. (转)MFC技巧学习五
  5. linux查看显卡核心数,linux查看硬件信息,linux查看硬盘信息,linux查看CPU信息,linux查看显卡,硬件型号信息 | 帮助信息-动天数据...
  6. Android的隐式意图
  7. jquery-ajax请求-1909
  8. 【面试】判断一棵二叉树是否为二叉排序树
  9. windows7修改双系统启动项名称、先后顺序、等待时间
  10. js html 处理json数据,JS中Json数据的处理和解析JSON数据的方法详解
  11. 发生了未经处理的异常
  12. 插入排序和Shell排序
  13. python获取图片大小_Python实现获取本地及远程图片大小的方法示例_python_脚本中心...
  14. MacOS自动操作Automator的技巧
  15. SVN客户端安装使用教程
  16. Caffe模型详细介绍
  17. java udp server_实现java UDP Server --2008农历新年第一贴(原创)
  18. plc c语言做报警,wincc声音报警C脚本版
  19. Windows系统改装成Linux系统
  20. 英文地址的翻译注意事项

热门文章

  1. LaTex入门教程-中文版-免费下载.pdf
  2. Echarts地图与图表联动
  3. 【MATLAB】画图汇总
  4. #0/1分数规划,SPFA,负环#洛谷 1768 天路
  5. 云计算不还是服务器吗,云计算和服务器可以说是一个概念吗?
  6. 零基础语法入门第八讲 实意动词的否定/提问/回答
  7. 7135制作自动量程电压切换_基于ICL7135和89S52单片机的数字电压表
  8. 操作系统内核和操作系统的区别
  9. IDR_MAINFRAME字符串资源含义
  10. (建设开发类)软件项目投资概算构成及参考样表