c# 网络通信
来源:互联网 发布:淘宝开企业店铺费用 编辑:程序博客网 时间:2024/04/27 07:23
c# 服务器端网络通信
最近的工作涉及到网络通信,在此小结一下这段时间的收获和遇到的问题。
一.通信方式:
1. Server/Client:
Server:Client :
1 : 1
1 : n(并发服务器方式)
n : 1(电驴,工控软件 ,额~我们的项目做客户端界面,也是如此的架构,不过目前只是1对1的,n对1需要创建多个连接,目前还没做)
2.连接方式
长连接
短连接
3.发送接收数据方式
异步
异步双工:接收和发送都在同一个程序中,有两个不同的子进程分别负责发送和接收。
异步单工:接收和发送是用两个不同的程序。
同步
报文发送后等待接收。同步通讯时,要考虑到超时。
下面贴一些最近学习网络编程时写的一些程序,我是用Socket调试工具调试完成了,不过还需要很多的改进。
Part .1 同步通信
public class SyncServer { public delegate void ActionMsgDelegate(object sender, ActionMsgEventArgs args); public event ActionMsgDelegate ActionMsgEvent; private IPAddress myIP= IPAddress.Parse("127.0.0.1"); private int myPort = 8000; private IPEndPoint myServer; private Socket socket; private bool check = true; private Socket acceptSocket; public static bool SocketServiceFlag = true; public SyncServer( string ip,int port ) { myIP = IPAddress.Parse(ip); myPort = port; } public void Accept( ) { myServer = new IPEndPoint(myIP, myPort); socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); Thread thread = new Thread(new ThreadStart( Receive)); thread.Start(); } public void Receive() { try { socket.Bind(myServer); socket.Listen(50); while (SocketServiceFlag) { acceptSocket = socket.Accept(); if (acceptSocket.Connected) { Thread thread = new Thread(new ThreadStart(Round)); thread.IsBackground = true; thread.Start(); } Thread.Sleep(1000); } } catch (Exception ex) { } } public void Round() { while( true ) { try { if (!acceptSocket.Connected||!check) { break; } Byte[] Rec = ReadData(); ///输出数据 if(Rec!=null) { string RecMessage = System.Text.Encoding.Default.GetString(Rec,0,Rec.Length); updateUI("接收数据:" + RecMessage); if (!check) { break; } string SendMessage = "返回数据:" + RecMessage; updateUI(SendMessage); byte[] sendByte = System.Text.Encoding.Default.GetBytes(SendMessage.ToCharArray()); SendData(sendByte); if (!check) { break; } } if (!check) { break; } } catch { } } } public Byte[] ReadData( ) { Byte[] Rec = new Byte[64]; int len = 0; try { if (!acceptSocket.Connected||!SocketServiceFlag) { check = false; return Rec; } NetworkStream netStream = new NetworkStream(acceptSocket); len=netStream.Read(Rec, 0, Rec.Length); Array.Resize( ref Rec, len);//重新调整RecBuffer的大小 } catch(SocketException ex) { if(len==0) { MessageBox.Show("连接断开"); check = false; } } if (len > 0) { return Rec; } return null; } public void SendData( Byte[] sendByte ) { try { if (!acceptSocket.Connected||!SocketServiceFlag) { check = false; return; } NetworkStream netStream = new NetworkStream(acceptSocket); netStream.WriteTimeout = 200; netStream.Write(sendByte, 0, sendByte.Length); }catch(Exception ex) { MessageBox.Show("发送数据有误:"+ex.Message); check = false; } } public void Close() { try { SocketServiceFlag = false; check = false; socket.Close(); } catch(Exception ex) { MessageBox.Show("关闭连接有误:"+ex.Message); } } public void updateUI( string message ) { ActionMsgEvent(this, new ActionMsgEventArgs("(" + DateTime.Now.ToLocalTime().ToString() + "):" + message + "\r\n")); } public void OnActionMsg(ActionMsgEventArgs args) { if (ActionMsgEvent != null) { ActionMsgEvent(this, args); } } }Part.2 使用TcpListener进行同步通信
public class TServer { public delegate void ActionMsgDelegate(object sender, ActionMsgEventArgs args); public event ActionMsgDelegate ActionMsgEvent; private int port = 8000; private TcpListener listener = null; private Socket mySocket = null; private NetworkStream netStream = null; private bool SocketServerFlag = true; public TServer( int port ) { this.port = port; } /// <summary> /// 启动监听 /// </summary> public void Accept( ) { listener = new TcpListener(port);//参数为端口号 listener.Start(); Thread thread = new Thread(new ThreadStart( Recieve)); thread.Start(); } /// <summary> /// 接收数据 /// </summary> public void Recieve( ) { try { while (SocketServerFlag) { if (listener.Pending()) { mySocket = listener.AcceptSocket(); if (mySocket.Connected) { Thread thread = new Thread(new ThreadStart(Round)); thread.Start(); } } Thread.Sleep(1000); } }catch(Exception ex) { MessageBox.Show(ex.Message ); } } /// <summary> /// 接收并发送数据 /// </summary> public void Round() { while (true) { Byte[] Rec = ReadData(); if( Rec!=null) { string RecMessage = System.Text.Encoding.Default.GetString(Rec); updateUI("接收数据:" + RecMessage); string SendMessage = "返回数据:" + RecMessage; updateUI(SendMessage); //界面显示 byte[] sendByte = System.Text.Encoding.Default.GetBytes(SendMessage.ToCharArray()); SendData(sendByte); } } } /// <summary> /// 读取数据局 /// </summary> /// <returns></returns> public Byte[] ReadData() { Byte[] Rec = new Byte[64]; int len = 0; try { if (!mySocket.Connected||!SocketServerFlag) { return Rec; } NetworkStream netStream = new NetworkStream(mySocket); len = netStream.Read(Rec, 0, Rec.Length); Array.Resize(ref Rec, len);//重新调整RecBuffer的大小 //string RecMessage = System.Text.Encoding.Default.GetString(Rec,0,len);//去除多余的\0数据 } catch (SocketException ex) { if (len == 0) { MessageBox.Show("连接断开"); } } if (len > 0) { return Rec; } return null; } /// <summary> /// 发送数据 /// </summary> /// <param name="messageByte"></param> public void SendData(byte[] messageByte) { try { if( mySocket.Connected && SocketServerFlag) { netStream = new NetworkStream(mySocket); netStream.Write(messageByte, 0, messageByte.Length); netStream.Flush(); } } catch (Exception ex) { } } /// <summary> /// 关闭连接 /// </summary> public void Close() { try { SocketServerFlag = false; mySocket.Close(); listener.Stop(); } catch(Exception ex) { MessageBox.Show("关闭连接异常"); } } /// <summary> /// 更新界面 /// </summary> /// <param name="message"></param> public void updateUI(string message) { ActionMsgEvent(this, new ActionMsgEventArgs("(" + DateTime.Now.ToLocalTime().ToString() + "):" + message + "\r\n")); } public void OnActionMsg(ActionMsgEventArgs args) { if (ActionMsgEvent != null) { ActionMsgEvent(this, args); } } }
Part .3 简单异步通信
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Net;using System.Net.Sockets;using System.Threading;using System.Windows.Forms;namespace ServerWork.Server{ public class StateObject { public Socket workSocket = null; public const int BufferSize = 1024; public byte[] buffer = new byte[BufferSize]; public StringBuilder sb = new StringBuilder(); public StateObject() { } } public class AsyncServer { public delegate void ActionMsgDelegate(object sender, ActionMsgEventArgs args); public event ActionMsgDelegate ActionMsgEvent; private IPAddress myIP = null; private int port = 8000; private IPEndPoint myServer; private Socket mySocket; private Socket handler; private static ManualResetEvent myReset = new ManualResetEvent(false);//ManualResetEvent建立时是把false作为start的初始状态,这个类用于通知另一个线程,让它等待一个或多个线程。 public bool SocketServerFlag = true; public bool blQuitListened = false; public AsyncServer( int port) { this.port = port; } public void Accept() { try { string strIP = getIPAddress(); myIP = IPAddress.Parse(strIP); myServer = new IPEndPoint(myIP, port); mySocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); mySocket.Bind(myServer); mySocket.Listen(50); Thread thread = new Thread(new ThreadStart(target)); thread.Start(); }catch(Exception ex) { MessageBox.Show(ex.Message); } } private string getIPAddress( ) { // 获得本机局域网IP地址 IPAddress[] AddressList = Dns.GetHostByName(Dns.GetHostName()).AddressList; if (AddressList.Length < 1) { return ""; } return AddressList[0].ToString(); } public void target() { while (!blQuitListened) { myReset.Reset(); mySocket.BeginAccept(new AsyncCallback(AcceptCallback), mySocket); myReset.WaitOne();//阻塞当前线程,知道收到请求信号 } } public void AcceptCallback(IAsyncResult ar) { myReset.Set();//将事件设为终止 Socket listener = (Socket)ar.AsyncState; if(blQuitListened) { SocketServerFlag = false; return; } handler = listener.EndAccept(ar); StateObject state = new StateObject();//获取状态 state.workSocket = handler;//与客户建立连接 SocketServerFlag = true; byte[] sendBuffer = System.Text.Encoding.Default.GetBytes("已经准备好监听"); SendData(sendBuffer ); Thread thread = new Thread(new ThreadStart(beginReceive)); //开启线程接收数据 thread.Start(); } public void SendData(byte[] sendData) { try { if( !handler.Connected||!SocketServerFlag) { return; } handler.BeginSend(sendData, 0, sendData.Length, 0, new AsyncCallback(SendCallback), handler); }catch( Exception ex) { MessageBox.Show(ex.Message); } } public void SendCallback(IAsyncResult ar) { try { handler = (Socket)ar.AsyncState; int bytesSent = handler.EndSend(ar); } catch (Exception ex) { MessageBox.Show(ex.Message); } } public void beginReceive( ) { try { StateObject state = new StateObject(); state.workSocket = handler; handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state); } catch (Exception ex) { MessageBox.Show("开始接收数据异常"); SocketServerFlag = false; } } public void ReadCallback(IAsyncResult ar) { try { StateObject state = (StateObject)ar.AsyncState; Socket tt = state.workSocket; if (!tt.Connected|| !SocketServerFlag) { return; } int bytesRead = handler.EndReceive(ar);//结束读取并获取字节数 if( bytesRead<1) { SocketServerFlag = false; return; } state.sb.Append(System.Text.Encoding.Default.GetString(state.buffer, 0, bytesRead)); string content = state.sb.ToString(); updateUI("接收数据:"+content ); state.sb.Remove(0, content.Length);//清除state.sb内容,准备重新复制 tt.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state); } catch (Exception ex) { MessageBox.Show("读取数据异常"); SocketServerFlag = false; } } public void updateUI(string message) { ActionMsgEvent(this, new ActionMsgEventArgs("(" + DateTime.Now.ToLocalTime().ToString() + "):" + message + "\r\n")); } public void OnActionMsg(ActionMsgEventArgs args) { if (ActionMsgEvent != null) { ActionMsgEvent(this, args); } } public void Close() { try { mySocket.Close(); } catch { MessageBox.Show("关闭网络连接异常"); } } }}上面程序中需要将一些发送接收的数据传递显示到界面上,所以有用到自定义的委托。
附winform中界面以及简单调用程序:
namespace ServerWork{ public partial class ServerForm : Form { public delegate void SetTextCallback(string text ); private SyncServer Server = null; private TServer tServer = null; private AsyncServer aServer = null; public ServerForm() { InitializeComponent(); } private void rtbShow_TextChanged(object sender, EventArgs e) { rtbShow.SelectionStart = rtbShow.Text.Length;//实现自动滚动显示追加内容 rtbShow.SelectionLength = 0; rtbShow.Focus(); } private void btnStart_Click(object sender, EventArgs e) { try { string strIPAddress = tbIPAddress.Text.Trim(); string strPort = tbPort.Text.Trim(); //Server = new SyncServer(strIPAddress, int.Parse(strPort)); //Server.ActionMsgEvent += new SyncServer.ActionMsgDelegate(UpdateRichText); //Server.Accept( ); //tServer = new TServer( int.Parse(strPort)); //tServer.ActionMsgEvent +=new TServer.ActionMsgDelegate(UpdateRichText); //tServer.Accept(); aServer = new AsyncServer(int.Parse(strPort)); aServer.ActionMsgEvent +=new AsyncServer.ActionMsgDelegate(UpdateRichText); aServer.Accept(); }catch(Exception ex) { MessageBox.Show("监听异常!"); } } private void btnSend_Click(object sender, EventArgs e) { //if(Server!=null&&Server.SocketServerFlag ) //{ // string sendData = rtbSend.Text; // byte[] buffer = System.Text.Encoding.Default.GetBytes(sendData); // Server.SendData( buffer ); // rtbShow.AppendText("(" + DateTime.Now.ToLocalTime().ToString() + "):" + sendData + "\r\n"); //} //if (tServer != null&&tServer.SocketServerFlag) //{ // string sendData = rtbSend.Text; // byte[] buffer = System.Text.Encoding.Default.GetBytes(sendData); // tServer.SendData(buffer); // rtbShow.AppendText("(" + DateTime.Now.ToLocalTime().ToString() + "):" + sendData + "\r\n"); //} if (aServer != null && aServer.SocketServerFlag) { string sendData = rtbSend.Text; byte[] buffer = System.Text.Encoding.Default.GetBytes(sendData); aServer.SendData(buffer); rtbShow.AppendText("(" + DateTime.Now.ToLocalTime().ToString() + "):发送数据:" + sendData + "\r\n"); } } private void btnStop_Click(object sender, EventArgs e) { try { //Server.Close();//关闭连接 // tServer.Close(); aServer.blQuitListened = true; aServer.Close(); }catch( Exception ex) { MessageBox.Show("关闭连接异常"); } } public void SetText(string text ) { if (this.rtbShow.InvokeRequired) { SetTextCallback d = new SetTextCallback(SetText); this.BeginInvoke(d, new object[] { text }); } else { this.rtbShow.AppendText(text); this.rtbShow.Refresh(); } } public void UpdateRichText(object sender, ActionMsgEventArgs e) { this.BeginInvoke((EventHandler)(delegate { rtbShow.AppendText(e.Message + "\r\n");//在richTextBox中追加内容 })); } }}在此做一小结,其实上面的服务器端程序写的还不完善,实际的工作中可能会需要很多复杂的情况。
比如,服务器端如何判断客户端关闭了连接;
客户端报文分发;(上面的程序中没有提到)
服务器端最多可连接多少个客户端并保持并发稳定性;
双向通信控制;
通信协议制度以及拆分拼包处理;(在写客户端程序时,我就遇到了此类问题)
数据接收到后是否有缓存机制;
如何快速找到要发送信息的客户端地址等问题都需要一一解决。
如果您有更好的建议,可以多多交流,互相学习。
- C#网络通信
- c#网络通信
- c# 网络通信
- C#网络通信
- c#网络通信实验教程
- C#网络通信:TCP连接
- c#下的Socket网络通信(类库)
- C#与网络通信研究(一)
- C# 网络编程实例 UDP TCP通信
- C# 利用socket实现语音网络通信
- C#实现简单的网络通信
- C# Socket网络通信初探(一)
- c#网络通信框架networkcomms内核解析
- C# 网络通信大小端转换类
- C# 通俗解释网络通信中的“报头”
- C#网络编程-简单的通信源码
- C#网络通信(2)--TCP编程和多线程
- DirectX编程:C#中利用Socket实现网络语音通信
- 一张图片上显示多个链接的例子
- hdu1754 I Hate It,线段树
- 代码注释要详细
- C++ Primer 第四版读书笔记(八)之顺序容器(续)
- java如何把jdbc驱动包打包
- c# 网络通信
- Extjs5.0(5):为项目添加左侧导航栏(treepanel)
- Nginx学习笔记(二)—— nginx中的rewrite
- 构建生成树算法----得到父节点的值
- Android四大组件之Activity详解——传值和获取结果
- Java 计算年平均增长率
- OpenCv每个模块的作用
- Java NIO简介
- 01-06-2015_线程池的概念