C#中服务器端以太网通讯(一对一)

作为服务器端,只需要知道自己需要监听的IP和端口号,就可以监听到前来通讯的服务器端。

可以使用一个结构体来封装TCP通讯所需要的参数。       

 static public Socket NewServer = null;
static public Socket NewClient = null;

public struct TcpSetPara
        {
            public IPAddress m_IP;          //监听的IP
            public int m_Port;                  //监听的Port
            public UInt16 CommTCPTimeSet;      //发送完报文后等待一段时间接收
        }

接着初始化参数

    public static void InitTcpPara()
        {
            m_TcpSetPara.CommTCPTimeSet = 200;
            m_TcpSetPara.m_IP = GetIpAddress();        //获取当前主机的IP
            m_TcpSetPara.m_Port = 502;
        }

//获取当前主机的IP     

public static IPAddress GetIpAddress()
        {
            string name = Dns.GetHostName();
            string IpStr = "";
            IPAddress[] ipadrlist = Dns.GetHostAddresses(name);
            foreach (IPAddress ipa in ipadrlist)
            {
                if (ipa.AddressFamily == AddressFamily.InterNetwork)
                {
                    IpStr = ipa.ToString();
                }
            }
            IPAddress ip = IPAddress.Parse(IpStr);
            return ip;
        }

启动连接,这里采用的是异步监听

static public void Connect()
        {
            //初始化TCP参数
            InitTcpPara();
            IPEndPoint point = new IPEndPoint(m_TcpSetPara.m_IP, m_TcpSetPara.m_Port);
            NewServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            NewServer.Bind(point);
            NewServer.Listen(50);
            NewServer.BeginAccept(new AsyncCallback(Accept), NewServer);

}

来看看Accept这个方法里都干了什么

 private static void Accept(IAsyncResult socket)
 {
            Socket SockeServer = (Socket)socket.AsyncState;
            // 在原始套接字上调用EndAccept方法,返回新的套接字
            NewClient = SockeServer.EndAccept(socket);

            bConnect = true;

      //起两个线程,一个用来发送,一个用来接收
            if (SendThread == null)
            {
                SendThread = new Thread(DataCommon.SendOperate);
                SendThread.Start();
                SendThread.IsBackground = true;
                //SendThread.Priority = ThreadPriority.Normal;
            }
            if (ProcessRevThread == null)
            {
                ProcessRevThread = new Thread(DataCommon.ProcessRevMessage);
                ProcessRevThread.Start();
                ProcessRevThread.IsBackground = true;
                //ProcessRevThread.Priority = ThreadPriority.Normal;
            }

           //为了确保当前的连接是有效的,需要不断检测,在这里用比较笨的办法

//由于在我的程序中,Connect这个方法本身是由线程启动的,所以在一个线程不断检测还是可以接收的

  while (bConnect)
            {
                bool flagRead = false;
                try
                {
                    flagRead = NewClient.Poll(10, SelectMode.SelectRead);
                }
                catch(Exception ex)
                {
                    //LogHelper.log(ex.ToString());
                    break;
                }
                if ((flagRead && (NewClient.Available == 0)) || !NewClient.Connected)
                {    

                 //这时可以确定网络连接出现问题,需要断开连接,重新连接

                    DisConnected();
                    bConnect = false;
                    ReConnect();
                }
                Thread.Sleep(1000);

 }

这时候得到的NewClient是一个有效的Socket,可以用来接收客户端的消息和向客户端发送消息

接收和发送消息也分为同步和异步

先来看一下同步接收:

private static int recv_cmd(byte[] recvbuffer, int buffer_len)
        {
            int recvlen = 0;
            try
            {
                Ethernet.Socket.ReceiveTimeout = 5000;                         //设置的接收消息超时
                Ethernet.NewClient.Blocking = false;
                recvlen = Ethernet.NewClient.Receive(recvbuffer, buffer_len, 0);
            }
            catch(Exception ex)
            {
                //Ethernet.bConnect = false;
                //MessageBox.Show("通讯异常!", "提示");
                //LogHelper.log(ex.Message.ToString());
                return -1;
            }
            return recvlen;
        }

再来看一下同步发送

  public static bool send_cmd(byte[] send_buffer, int buffer_len)
        {
            bool bSend_succ = false;
            try
            {
                Ethernet.Socket.Blocking = false;
                Ethernet.Socket.SendTimeout = 500;                 //设置的发送超时
                Ethernet.Socket.Send(send_buffer, buffer_len, 0);
                bSend_succ = true;
            }
            catch(Exception ex)
            {
                //LogHelper.log(ex.Message.ToString());
                bSend_succ = false;
            }
            return bSend_succ;
        }

来看一下异步接收:

  public static void ProcessMaintenenceMessage()
        {
   NewClient.BeginReceive(recvbuffer, 0, recvbuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), NewClient);
        }

static void ReceiveCallback(IAsyncResult result)
        {
            Socket ts = (Socket)result.AsyncState;
            try
            {
                ts.EndReceive(result);
                result.AsyncWaitHandle.Close();
                //接收到消息后开始处理消息的线程
                //ProcessMessageThread = new Thread(ProcessOneKeyDataProcess);
                //ProcessMessageThread.Start(recvbuffer);

                //将数据存入到队列中
                lock(m_OneKeyMaintence)
                {
                    m_OneKeyMaintence.Enqueue(recvbuffer);
                }

                //等待100ms继续接收消息
                Thread.Sleep(500);
                recvbuffer = new byte[recvbuffer.Length];
                ts.BeginReceive(recvbuffer, 0, recvbuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), ts);
            }
            catch(Exception ex)    //Socket对象已关闭
            {
                //接收消息时出现异常,重新连接
                DisConnect();
                ReConnect();
                //LogHelper.log(ex.Message.ToString());
                return;
            }
        }

以上是做完项目后的一个大体梳理,如有问题,敬请指出

猜你喜欢

转载自blog.csdn.net/una_ting/article/details/81535824