利用Socket建立基礎連線

以C#為例,在伺服器端需要建立兩個Socket,一個用來監聽客戶所傳過來的訊息,另外一個用來回傳訊息給客戶;客戶端方面則需要一個Socket來傳送客戶所要傳送的訊息。

什麼是Socket?我們要聯絡需要打電話,而兩個應用程序之間的聯絡則是透過Socket,透過Socket電腦可以配合不同的方法完成不同的傳輸工作。

以下是在傳送資料時,需要用到的數據:

協議:就像兩個人要溝通需要經由同一種語言,程序和程序之間的溝通,也必須要同一種協議,常見的網路協議包括有,HTTP網頁常用的協議,FTP傳送檔案常用的協議。

IP:電腦主機在網路上的地址,就像我們房子有住址一樣,這個地址可以提供網際網路服務業者搜尋到封包該被傳送到的正確位置,目前基本上是利用IP4為主要的IP類型。

端口:一台電腦當下只有一個 IP,但是電腦中運行的應用程序都擁有自己一個端口號。

TCP:一種傳輸的協定,一種安全度高的傳輸協定,比較不會有數據丟失的情狀發生,但是傳送效率較低,利用Stream類型的Socket來傳送。可用來來傳輸檔案以及聊天訊息,比較不適合用來當作網路影音的傳輸協定。

使用TCP協議傳輸時,先由客戶端發出訊息,詢問伺服器,“您有空嗎?”,再由伺服器回覆給客戶端,”我現在有空“,當客戶端接收到了伺服器算傳來的訊息後,會再發最後一則訊息給伺服器,“我有收到你現在有空的訊息”。這三次傳送俗稱”三次握手“,此目的是為了確定伺服器可以接收和響應回饋給客戶。

UDP:傳輸協定的一種,一種安全度較低的傳輸協定,容易有數據丟失的形況發生,利用Datagram數據棒類型的Socket傳送,多用於影音串流技術。

  • 傳輸過程中是利用byte二進制來傳送。

基本流程圖:

簡單伺服器端口架設

講解代碼如下:

using System;
using System.Net;
using System.Net.Sockets;
//建立一個監聽用Socket
static Socket socketListener;
//建立一個Server方法
public static void Server(int myPort,int allowNum){ 
//實作監聽用Socket,
//AddressFamily.InterNetwork表示利用IP4協議
//SocketType.Stream 因為我們要使用TCP協議,需使用流式的Socket
//ProtocolType.Tcp 選用TCP協議
socketListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//指定伺服器IP,這邊利用IPAddress.Any方法得到本機的IP,讓這方法可以運用更靈活
IPAddress ip = IPAddress.Any;
//設置應用程序的端口
int port = myPort;
//利用IPEndPoint這個類,將伺服器端的IP還有端口帶入給socketListener
IPEndPoint point = new IPEndPoint(ip, port);
//將point綁定給socketListener
socketListener.Bind(point);

ShowMsg("Listening...");
//設定幾個程序可以連至本伺服器
socketListener.Listen(allowNum);
}

//傳送訊息
private static void ShowMsg(string s)
{
    Console.WriteLine(s);
}

//建立Server中用來傳送資料給客戶端的Socket
public static void ServerSender(Socket listener)
{ 
//利用Accept方法接收監聽用Socket資料
Socket socketSender = listener.Accept();
//如果連線成功利用socketSender.RemoteEndPoint取得所連線到的Socket的IP和Port
ShowMsg(("Client IP = " + socketSender.RemoteEndPoint.ToString()) + " Connect Succese!");
}

public static void Main(string[] args)
{
//將端口設置為6000,設定三個應用程序可以連線到伺服器
Server(60000,3);
//取得客戶端資料
ServerSender(socketListener);
}

可以利用telnet測試本程式

首先運行伺服器端程式

開啟Terminal,輸入telnet ip port 自己在server端口的資料測試

例如在主控台輸入

telnet 192.123.123.123 60000

Terminal中輸入

lsof -i tcp 顯示所有使用TCP協議的應用程序

lsof -i udp 顯示所有使用UDP協議的應用程序

lsof -i tcp:port 顯示該端口所使用的應用程序

完整程序代碼如下:

using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace SocketDemo
{
    class MainClass
    {
        static Socket socketListener;

        public static void Main(string[] args)
        {
            ServerEnd(60000,1);
            Thread th = new Thread(ServerSender);
            th.Start(socketListener);
        }

        public static void ServerEnd(int myPort,int allowNum)
        { 
            socketListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            IPAddress ip = IPAddress.Any;

            int port = myPort;

            IPEndPoint point = new IPEndPoint(ip, port);

            socketListener.Bind(point);

            ShowMsg("Listening...");

            socketListener.Listen(allowNum);
        }

        public static void ServerSender(object obListener)
        {
            Socket temp = (Socket)obListener;

            Socket socketSender = temp.Accept();

            ShowMsg(("Client IP = " + socketSender.RemoteEndPoint.ToString()) + " Connect Succese!");
        }


        private static void ShowMsg(string s)
        {
            Console.WriteLine(s);
        }

    }

}

Socket和Thread使用範例(可多人連線到伺服器):

using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace SocketDemo
{
    class MainClass
    {
        static Socket socketListener;

        public static void Main(string[] args)
        {
            ServerEnd(60000,10);
            Thread th = new Thread(ServerSender);
            th.Start(socketListener);
        }

        public static void ServerEnd(int myPort,int allowNum)
        { 
            socketListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            IPAddress ip = IPAddress.Any;

            int port = myPort;

            IPEndPoint point = new IPEndPoint(ip, port);

            socketListener.Bind(point);

            ShowMsg("Listening...");

            socketListener.Listen(allowNum);
        }

        public static void ServerSender(object obListener)
        {
            Socket temp = obListener as Socket;

            while (true)
            {
                Socket socketSender = temp.Accept();

                ShowMsg(("Client IP = " + socketSender.RemoteEndPoint.ToString()) + " Connect Succese!");
            }
        }

        private static void ShowMsg(string s)
        {
            Console.WriteLine(s);
        }

    }

}

讀取客戶所傳送的資訊

using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace SocketDemo
{
    class MainClass
    {
        static Socket socketListener;

        public static void Main(string[] args)
        {
            ServerEnd(60000, 10);
            Thread th = new Thread(ServerSender);
            th.Start(socketListener);
        }

        public static void ServerEnd(int myPort, int allowNum)
        {
            socketListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            IPAddress ip = IPAddress.Any;

            int port = myPort;

            IPEndPoint point = new IPEndPoint(ip, port);

            socketListener.Bind(point);

            ShowMsg("Listening...");

            socketListener.Listen(allowNum);
        }

        public static void ServerSender(object obListener)
        {
            Socket temp = (Socket)obListener;

            while (true)
            { 
                Socket socketSender = temp.Accept();

                ShowMsg(("Client IP = " + socketSender.RemoteEndPoint.ToString()) + " Connect Succese!");
                //加開一個線程可重複接收客戶端所傳回的資料
                Thread th1 = new Thread(ReceiveClient);
                //准許線程在背景執行
                th1.IsBackground = true;
                //啟動線程
                th1.Start(socketSender);
            }

        }

        static void ReceiveClient(object mySocketSender)
        {
            Socket socketSender = mySocketSender as Socket;

            while (true)
            { 
                //數據傳送是由數組的方式傳送,創立一個數組來儲存客戶端所回傳的訊息
                byte[] buffer = new byte[1024];
                 //讀取字節數
                int rece = socketSender.Receive(buffer);
                //如果客戶端離開所得到的字節數會等於0,跳出此循環
        if (rece == 0)
        {
            ShowMsg(string.Format("Client : {0} + 下線了", socketSender.RemoteEndPoint.ToString()));
             break;
        }

                //載入System.Text的命名空間,利用GetString方法讀取字節,
                //第一個引數代表要讀取的byte[]
                //第二個引數代表從左邊數來第幾個字開始讀取
                //每次讀取的字節數
                string clientMsg = Encoding.UTF8.GetString(buffer, 0, rece);
                ShowMsg(string.Format("Client : {0}", clientMsg));
            }
        }


        private static void ShowMsg(string s)
        {
            Console.WriteLine(s);
        }

    }

}
  1. 開啟伺服器程式
  2. 開啟Terminal 利用telnet ip port連接至伺服器
  3. 連接完後所輸入的文字將被讀取到伺服器的Terminal中

以下為客戶端與伺服器端互傳訊息Demo

伺服器端:

using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace SocketDemo
{
    class MainClass
    {
        static Socket socketListener;

        public static void Main(string[] args)
        {
            ServerEnd(60000, 10);
            Thread th = new Thread(ServerCommunity);
            th.Start(socketListener);
        }

        private static void ServerEnd(int myPort, int allowNum)
        {
            socketListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            IPAddress ip = IPAddress.Any;

            int port = myPort;

            IPEndPoint point = new IPEndPoint(ip, port);

            socketListener.Bind(point);

            ShowMsg("Listening...");

            socketListener.Listen(allowNum);
        }

        private static void ServerCommunity(object obListener)
        {
            Socket temp = (Socket)obListener;

            while (true)
            { 
                Socket socketSender = temp.Accept();

                ShowMsg(("Client IP = " + socketSender.RemoteEndPoint.ToString()) + " Connect Succese!");

                Thread ReceiveMsg = new Thread(ReceiveClient);

                ReceiveMsg.IsBackground = true;

                Thread SendToClient = new Thread(SendMsgToClient);

                SendToClient.Start(socketSender);

                ReceiveMsg.Start(socketSender);
            }

        }

        private static void SendMsgToClient(object mySocketSender)
        { 
            Socket socketSender = mySocketSender as Socket;

            while (true)
            {
                if (socketSender.RemoteEndPoint == null)
                {
                    ShowMsg("socketSender.RemoteEndPoint == null");
                    break;
                }
                string msg = Console.ReadLine();

                byte[] buffer = Encoding.UTF8.GetBytes(msg);

                socketSender.Send(buffer);
            }

        }

        private static void ReceiveClient(object mySocketSender)
        {
            Socket socketSender = mySocketSender as Socket;

            while (true)
            { 

                byte[] buffer = new byte[1024];

                int rece = socketSender.Receive(buffer);

                if (rece == 0)
                {
                    ShowMsg(string.Format("Client : {0} + 下線了", socketSender.RemoteEndPoint.ToString()));
                    break;
                }
                string clientMsg = Encoding.UTF8.GetString(buffer, 0, rece);
                ShowMsg(string.Format("Client : {0}", clientMsg));
            }
        }


        private static void ShowMsg(string s)
        {
            Console.WriteLine(s);
        }

    }

}

客戶端:

using System;
using System.Threading;
using System.Net.Sockets;
using System.Net;

namespace Socket_Client_Demo
{
    class MainClass
    {
        public static void Main(string[] args)
        {
            Console.WriteLine("請輸入IP");

            string ip = Console.ReadLine();

            Console.WriteLine("請輸入端口號");

            int port =int.Parse(Console.ReadLine());

            ClientSocket(ip,port);
        }

        private static Socket socket;

        private static void ClientSocket(string ip,int port)
        {
            socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);

            IPAddress myIp = IPAddress.Parse(ip);

            IPEndPoint point = new IPEndPoint(myIp,port);

            socket.Connect(point);

            ShowMsg("Connect Succese! "+socket.RemoteEndPoint.ToString());

            Thread sendMsg = new Thread(SendMsgToServer);

            Thread ReceiveMsg = new Thread(ReceiveMsgFromServer);

            ReceiveMsg.IsBackground = true;

            ReceiveMsg.Start();

            sendMsg.Start();

        }

        private static void ReceiveMsgFromServer()
        {
            while (true)
            { 
                byte[] buffer = new byte[1024];

                int rec = socket.Receive(buffer);

                if (rec == 0)
                { 
                    ShowMsg("Server Loss!");
                    break;
                }

                string receText = System.Text.Encoding.UTF8.GetString(buffer, 0, rec);

                ShowMsg("Server :" + receText);
            }
        }

        private static void SendMsgToServer()
        {
            while (true)
            {

                string inputText = Console.ReadLine();

                byte[] buffer = System.Text.Encoding.UTF8.GetBytes(inputText);

                socket.Send(buffer);
            }
        }

        private static void ShowMsg(string s)
        { 
            Console.WriteLine(s);
        }
    }
}

results matching ""

    No results matching ""