1. 程式人生 > >socket通訊問題

socket通訊問題

2015年12月11日 14:55:04 yiqijinbu 閱讀數:3035

TCP:面向連線的,所以在服務端繫結埠後,需要監聽Listen()是否有客戶端傳送請求,有的話,Accept()建立一個新的socket物件,用於傳送和接收資訊,

            就想先建造了一條高速路,再建造一輛貨車拉貨。

UDP:無連線的,所以在服務端繫結埠後,不需要監聽Listen(),也不用建立一個新的socket物件用於接收發送資訊,但是在傳送和接收時,要講本身的埠

   做引數傳送給對方,這樣在交流時,對方才能確定自己。

 

UDP協議:

Client端:

static void Main(string[] args)
        {
            int port = 2001;
            string strHost = GetAddressIP();// "127.0.0.1";
            //  建立IP物件
            IPAddress ip = IPAddress.Parse(strHost);
            //  建立埠物件
            IPEndPoint ipe = new IPEndPoint(ip, port);
 
 
            //  建立socket物件
            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            Console.WriteLine("連線中。。。");
 
 
            //  向伺服器傳送訊息
            string strMsgToServe = "嗨,來自客戶端的問候。。。";
            //  轉成二進位制傳送到服務端
            byte[] bytMsgToServe = Encoding.UTF8.GetBytes(strMsgToServe);
            socket.SendTo(bytMsgToServe, bytMsgToServe.Length, SocketFlags.None, ipe);
            Console.WriteLine("訊息已傳送。。。");
 
 
            //IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
            EndPoint Remote = new IPEndPoint(IPAddress.Any, 0);//(EndPoint)sender;
            bytMsgToServe = new byte[1024];
            int recv = socket.ReceiveFrom(bytMsgToServe, ref Remote);//接受來自伺服器的資料
 
 
            Console.WriteLine("Message received from{0}:", Remote.ToString());
            Console.WriteLine("收到的服務端訊息:"+Encoding.UTF8.GetString(bytMsgToServe, 0, recv));
            socket.Close();
            Console.ReadLine();
        }
 
 
        /// <summary>
        /// 獲取本地IP地址資訊
        /// </summary>
        public static string GetAddressIP()
        {
            ///獲取本地的IP地址
            string AddressIP = string.Empty;
            foreach (IPAddress _IPAddress in Dns.GetHostEntry(Dns.GetHostName()).AddressList)
            {
                if (_IPAddress.AddressFamily.ToString() == "InterNetwork")
                {
                    AddressIP = _IPAddress.ToString();
                }
            }
            return AddressIP;
        }


Server端:

static void Main(string[] args)
        {
            int port = 2001;
            string strHost = GetAddressIP();// "127.0.0.1";
            //  建立終結點
            IPAddress ip = IPAddress.Parse(strHost);
            //  建立網路埠
            IPEndPoint ipe = new IPEndPoint(ip, port);
 
            //  建立socke,開始監聽--SocketType列舉
            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            //  繫結埠
            socket.Bind(ipe);
            Console.WriteLine("等待客戶端連線。。。");
 
            //IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);//定義要傳送的計算機的地址
            EndPoint Remote = new IPEndPoint(IPAddress.Any, 0);//(EndPoint)(sender);
 
            //  收到的二進位制byte
            byte[] bytRecv = new byte[1024];
            int intBytes = socket.ReceiveFrom(bytRecv, ref Remote);//接受來自伺服器的資料          
            //Console.WriteLine("Message received from{0}:", Remote.ToString());
            Console.WriteLine("收到的資訊:-"+Encoding.UTF8.GetString(bytRecv, 0, intBytes));
 
            string welcome = "Welcome to my test server!";
            bytRecv = Encoding.ASCII.GetBytes(welcome);
            socket.SendTo(bytRecv, bytRecv.Length, SocketFlags.None, Remote);
            Console.ReadLine();
        }
        /// <summary>
        /// 獲取本地IP地址資訊
        /// </summary>
        public static string GetAddressIP()
        {
            ///獲取本地的IP地址
            string AddressIP = string.Empty;
            foreach (IPAddress _IPAddress in Dns.GetHostEntry(Dns.GetHostName()).AddressList)
            {
                if (_IPAddress.AddressFamily.ToString() == "InterNetwork")
                {
                    AddressIP = _IPAddress.ToString();
                }
            }
            return AddressIP;
        }

當將服務層寫成window服務時,如果客戶端關閉,服務端會報錯,“遠端主機關閉了一個現有的連結”,然後整個服務都停止了。

解決辦法:為socket物件設定低階操作模式

//  為 Socket 設定低階操作模式,不然當客戶端關閉的時候,會報錯
            uint IOC_IN = 0x80000000;
            uint IOC_VENDOR = 0x18000000;
            uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
            socket.IOControl((int)SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, null);

另外,在window服務中,定時控制元件是不能用的,但是也不報錯,不提醒,如果要定時迴圈,

解決辦法:

            System.Timers.Timer tmrSelectCOM = new System.Timers.Timer(2000);
            tmrSelectCOM.Elapsed += new System.Timers.ElapsedEventHandler(tmrSelectCOM_Tick);
            tmrSelectCOM.Enabled = true;

TCP協議:

服務端:

static void Main(string[] args)
        {
            //  ip地址,埠
            int port = 2000;
            string strIp = GetAddressIP();
            //  IP物件
            IPAddress ip = IPAddress.Parse(strIp);
            IPEndPoint ipe = new IPEndPoint(ip, port);
            //  例項化socket物件
            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //  繫結埠
            socket.Bind(ipe);
            //  監聽
            socket.Listen(0);
            //  為傳送請求的客戶端建立新的socket物件
            Socket temp = socket.Accept();
 
            //  接收訊息
            byte[] bytRecv = new byte[1024];
            int intCount = temp.Receive(bytRecv,bytRecv.Length,0);
            string strRecv = Encoding.UTF8.GetString(bytRecv, 0, intCount);
            Console.WriteLine(strRecv);
 
            //  傳送訊息
            string strSendMsg = "來自服務端的問候。。。";
            byte[] bytSendMsg = Encoding.UTF8.GetBytes(strSendMsg);
            temp.Send(bytSendMsg, 0, bytSendMsg.Length, 0);
            Console.WriteLine("服務端訊息已傳送。。。");
            Console.ReadLine();
        }
 
        private static string GetAddressIP()
        {
            string strAddressIP = string.Empty;
            foreach (IPAddress address in Dns.GetHostEntry(Dns.GetHostName()).AddressList)
            {
                if (address.AddressFamily.ToString() == "InterNetwork")
                {
                    strAddressIP = address.ToString();
                }
            }
            return strAddressIP;
        }
  1. 客戶端:
public static void Main(string[] args)
        {
            int port = 2000;
            string strIp = GetAddressIP();
            //  IP物件
            IPAddress ip = IPAddress.Parse(strIp);
            IPEndPoint ipe = new IPEndPoint(ip, port);
            //  建立socket物件
            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //  連線
            socket.Connect(ipe);
            Console.WriteLine("已連線。。。");
 
            //  傳送資訊
            string strSendMsg="來自客戶端的問候。。。";
            byte[] bytSendMsg = Encoding.UTF8.GetBytes(strSendMsg);
            socket.Send(bytSendMsg, 0, bytSendMsg.Length, SocketFlags.None);
            Console.WriteLine("訊息已傳送。。。");
            //  接收
            byte[] bytRecvMsg = new byte[1024];
            int intCount = socket.Receive(bytRecvMsg);
            string strRecvMsg = Encoding.UTF8.GetString(bytRecvMsg, 0, intCount);
            Console.WriteLine(strRecvMsg);
            Console.ReadLine();
        }
 
        private static string GetAddressIP()
        {
            //  獲取本地的IP地址
            string AddressIP = string.Empty;
            foreach (IPAddress _IPAddress in Dns.GetHostEntry(Dns.GetHostName()).AddressList)
            {
                if (_IPAddress.AddressFamily.ToString() == "InterNetwork")
                {
                    AddressIP = _IPAddress.ToString();
                }
            }
            return AddressIP;
        }

TCP圖:

UDP圖: