天天看點

淺談TCP通訊

基于Tcp協定的Socket通訊類似于B/S架構,面向連接配接,但不同的是伺服器端可以向用戶端主動推送消息。

使用Tcp協定通訊需要具備以下幾個條件:

    (1).建立一個套接字(Socket)

    (2).綁定伺服器端IP位址及端口号--伺服器端

    (3).利用Listen()方法開啟監聽--伺服器端

    (4).利用Accept()方法嘗試與用戶端建立一個連接配接--伺服器端

    (5).利用Connect()方法與伺服器建立連接配接--用戶端

    (5).利用Send()方法向建立連接配接的主機發送消息

    (6).利用Recive()方法接受來自建立連接配接的主機的消息(可靠連接配接)

以下為個人平時編寫的執行個體

TCP服務端執行個體

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Net;

namespace TcpServerConsoleApp
{
    class Program
    {
        /// <summary>
        /// 伺服器端的監聽器
        /// </summary>
        private static TcpListener _tcpl = null;
        /// <summary>
        /// 本機IP位址
        /// </summary>
        private static IPAddress _ip = null;

        private static int _port = 9005;

        static void Main(string[] args)
        {
            GetLocationIp();//擷取IP位址
            StartTcpServer();//啟動

        }


        private static void GetLocationIp()
        {
            //IP4擷取IP位址
            //IPAddress _ip = Dns.GetHostAddresses(Dns.GetHostName())[0];//可能有多個,此時的IP是本地IP

            //如果在IP6的需要以下發送擷取IP位址
            IPHostEntry IpEntry = Dns.GetHostEntry(Dns.GetHostName());
            for (int i = 0; i < IpEntry.AddressList.Length; i++)
            {
                //從IP位址清單中篩選出IPv4類型的IP位址
                //AddressFamily.InterNetwork表示此IP為IPv4,
                //AddressFamily.InterNetworkV6表示此位址為IPv6類型
                if (IpEntry.AddressList[i].AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                {
                    _ip = IpEntry.AddressList[i];
                    break;
                }
            }

            
        }

        /// <summary>
        /// 啟動TCP伺服器
        /// </summary>
        /// <param name="port"></param>
        private static void StartTcpServer()
        {
            try
            {
                _tcpl = new TcpListener(_ip, _port);
                _tcpl.Start();
                Console.WriteLine("伺服器已啟動,正在監聽...
");
                Console.WriteLine(string.Format("伺服器IP:{0}	端口号:{1}
", _ip, _port));
                //AcceptSocket 是一個阻止方法,該方法傳回可用于發送和接收資料的 Socket。
                //如果希望避免阻止,請使用 Pending 方法來确定傳入連接配接隊列中的連接配接請求是否可用。 
                //傳回的 Socket 是使用遠端主機的 IP 位址和端口号初始化的。
                //您可以使用 Socket 類中任何可用的 Send 和 Receive 方法與遠端主機進行通信。
                //------------使用 Socket 後,請確定調用其 Close 方法。如果應用程式相對簡單,-----------
                //請考慮使用 AcceptTcpClient 方法代替 AcceptSocket 方法。
                //TcpClient 提供了一些通過網絡在阻止同步模式下發送和接收資料的簡單方法。

                Socket newClient = _tcpl.AcceptSocket();//本地TcpListener 接受新的請求 
                //傳回的 Socket 是使用遠端主機的 IP 位址和端口号初始化的

                //byte[] packetBuff = new byte[10 * 1024];//接收資料緩沖區大小10K
                //newClient.Receive(packetBuff);

                Console.WriteLine("接入客服端:{0}", newClient.RemoteEndPoint.ToString());

                Thread clientThread = new Thread(() => ThrendReciveFunc(newClient));
                clientThread.Start();
            }
            catch
            { }

        }

        /// <summary>
        /// 接收子線程
        /// </summary>
        /// <param name="socketClient"></param>
        private static void ThrendReciveFunc(Socket socketClient)
        {
            while (true)
            {
                try
                {
                    byte[] buffer = new byte[10 * 1024];//接收資料緩沖區
                    int count = socketClient.Receive(buffer);
                    string msg = Encoding.Default.GetString(buffer, 0, count);
                    Console.WriteLine("收到消息:{0}", msg);
                    string sendmsg = "收到消息!";
                    socketClient.Send(Encoding.Default.GetBytes(sendmsg));
                }
                catch (Exception ex)
                {
                    Console.WriteLine(string.Format("出現異常:{0}", ex.Message));
                    Thread.CurrentThread.Abort();//結束該接收線程
                    Console.Read();
                    break;
                }
            }
        }
       



    }
}      

TCP客服端執行個體

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace TcpClientConsolApp
{
    class Program
    {
        static IPAddress _ip = null;
        static TcpClient _tcpc;
        static NetworkStream Netstream;//提供用于通路網絡的基本資料流
        static void Main(string[] args)
        {
            Console.WriteLine("請輸入IP位址:");
            GetIpAddr();
            Console.WriteLine("請輸入端口号:");
            int port = Convert.ToInt16(Console.ReadLine());
            try
            {
                _tcpc = new TcpClient();
                _tcpc.Connect(_ip, port);
                if (_tcpc != null)
                {
                    Console.WriteLine("連接配接成功");
                    Netstream = _tcpc.GetStream();
                    Thread recvieThread = new Thread(RecvieFunc);
                    recvieThread.Start();
                    
                    /*發送資料*/
                    while (true)
                    {
                        Console.WriteLine("輸入要發送的資料");
                        byte[] msg = Encoding.Default.GetBytes(Console.ReadLine());
                        Netstream.Write(msg, 0, msg.Length);
                    }
                }
                else
                {
                    Console.WriteLine("連接配接失敗!");
                }
            }
            catch
            { }

            Console.Read();

        }

        static void GetIpAddr()
        {
            try
            {
                _ip = IPAddress.Parse(Console.ReadLine());
            }
            catch
            {
 
            }
            if (_ip == null)
            {
                Console.WriteLine("輸入IP位址有誤,請重新輸入");
                GetIpAddr();
            }
        }

        /// <summary>
        /// 接收線程
        /// </summary>
        static void RecvieFunc()
        {
            while (_tcpc.Client.Connected)
            {
                try
                {
                    byte[] buffer = new byte[10 * 1024];
                    int count = _tcpc.Client.Receive(buffer);
                    string msg = Encoding.Default.GetString(buffer, 0, count);
                    Console.WriteLine("接收到資訊:{0}", msg);

                }
                catch (Exception ex)
                {
                    Console.WriteLine(string.Format("出現異常:{0}", ex.Message));
                    //Netstream = null;
                    Netstream.Close();
                    Thread.CurrentThread.Abort();
                    break;
                }
            }
        }
    }
}