c# 网络通信

                                                                                               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;}/// /// 启动监听/// public void Accept( ){listener = new TcpListener(port);//参数为端口号listener.Start();Thread thread = new Thread(new ThreadStart( Recieve));thread.Start();}/// /// 接收数据/// 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 );}}/// /// 接收并发送数据/// 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);}}}/// /// 读取数据局/// /// 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;}/// /// 发送数据/// /// 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){}}/// /// 关闭连接/// public void Close(){try{SocketServerFlag = false;mySocket.Close();listener.Stop();}catch(Exception ex){MessageBox.Show("关闭连接异常");}}/// /// 更新界面/// /// 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中追加内容}));}}
}
在此做一小结,其实上面的服务器端程序写的还不完善,实际的工作中可能会需要很多复杂的情况。

比如,服务器端如何判断客户端关闭了连接;

客户端报文分发;(上面的程序中没有提到)

服务器端最多可连接多少个客户端并保持并发稳定性;

双向通信控制;

通信协议制度以及拆分拼包处理;(微笑在写客户端程序时,我就遇到了此类问题)

数据接收到后是否有缓存机制;

如何快速找到要发送信息的客户端地址等问题都需要一一解决。

如果您有更好的建议,可以多多交流,互相学习。



  



本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部