1. 程式人生 > 實用技巧 >dotnet socket

dotnet socket

服務端操作

//1、建立IPE
int port = 6000;
string host = "127.0.0.1";
IPAddress ip = IPAddress.Parse(host);
IPEndPoint ipe = new IPEndPoint(ip, port);

//2、建立socket
Socket sSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//3、繫結埠與ip
//如果要指定本地 IP 地址和埠號,請在呼叫 Listen 方法之前呼叫 Bind 方法
sSocket.Bind(ipe);
//4、監聽,如果希望基礎服務提供商為你分配一個可用埠,請使用埠號零
//如果使用面向連線的協議(例如 TCP),則伺服器可以使用 Listen 方法偵聽連線
sSocket.Listen(0);

Console.WriteLine("監聽已經開啟,請等待");

//5、獲取通訊socket
//receive message, Accept 方法處理任何傳入連線請求,並返回可用於與遠端主機通訊的 Socket
Socket serverSocket = sSocket.Accept();

Console.WriteLine("連線已經建立");
string recStr = "";
byte[] recByte = new byte[4096];
//6、接收資料。若要傳遞資料,請呼叫 Send 或 Receive 方法
int bytes = serverSocket.Receive(recByte, recByte.Length, 0);
recStr += Encoding.ASCII.GetString(recByte, 0, bytes);

//send message
Console.WriteLine("伺服器端獲得資訊:{0}", recStr);
string sendStr = "send to client :hello";
byte[] sendByte = Encoding.ASCII.GetBytes(sendStr);
//7、傳送資料
serverSocket.Send(sendByte, sendByte.Length, 0);
serverSocket.Close();
sSocket.Close();

client

//1、建立ipe
int port = 6000;
string host = "127.0.0.1";//伺服器端ip地址
IPAddress ip = IPAddress.Parse(host);
IPEndPoint ipe = new IPEndPoint(ip, port);

//2、建立socket
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//3、connect
clientSocket.Connect(ipe);

//4、send message
string sendStr = "send to server : hello,ni hao";
byte[] sendBytes = Encoding.ASCII.GetBytes(sendStr);
clientSocket.Send(sendBytes);

//5、receive message
string recStr = "";
byte[] recBytes = new byte[4096];
int bytes = clientSocket.Receive(recBytes, recBytes.Length, 0);
recStr += Encoding.ASCII.GetString(recBytes, 0, bytes);
Console.WriteLine(recStr);

clientSocket.Close();

下面的程式碼實現非同步:

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

// 客戶端請求狀態資訊儲存在這裡
public class StateObject
{
    // Client socket. 
    // 客戶端的socket
    public Socket workSocket = null;
    // Size of receive buffer.  
    public const int BufferSize = 1024;
    // Receive buffer.  
    public byte[] buffer = new byte[BufferSize];
    // Received data string.  
    public StringBuilder sb = new StringBuilder();
}

public class AsynchronousSocketListener
{

    public static List<Socket> ClientSockets = new List<Socket>();

    // 執行緒訊號  
    public static ManualResetEvent allDone = new ManualResetEvent(false);
    
    /// <summary>
    /// 建構函式
    /// </summary>
    public AsynchronousSocketListener()
    {
    }

    /// <summary>
    /// 開始監聽
    /// </summary>
    public static void StartListening()
    {
        // Establish the local endpoint for the socket.  
        // The DNS name of the computer  
        // running the listener is "host.contoso.com".  
        IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
        IPAddress ipAddress = ipHostInfo.AddressList[3];
        IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);

        // Create a TCP/IP socket.  
        Socket listener = new Socket(ipAddress.AddressFamily,
            SocketType.Stream, ProtocolType.Tcp);

        // Bind the socket to the local endpoint and listen for incoming connections.  
        try
        {
            listener.Bind(localEndPoint);
            listener.Listen(100);
            Task.Run(()=> {
                while (true)
                {
                    // Set the event to nonsignaled state.  
                    allDone.Reset();

                    // Start an asynchronous socket to listen for connections. 
                    // AsyncCallback 讓回撥函式在單獨的執行緒中執行
                    Console.WriteLine("Waiting for a connection...");
                    // 處理傳入的請求
                    listener.BeginAccept(
                        new AsyncCallback(AcceptCallback),
                        listener);

                    // Wait until a connection is made before continuing.                  
                    allDone.WaitOne();
                }
            });

            while (true)
            {

                for (int i = 0; i < ClientSockets.Count; i++)
                {
                    try
                    {
                        Send(ClientSockets[i], "hello i am server\r\n");
                    }
                    catch (Exception)
                    {
                        ClientSockets.RemoveAt(i);
                    }
                }
                Thread.Sleep(100);
            }


        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }

        Console.WriteLine("\nPress ENTER to continue...");
        Console.Read();

    }

    /// <summary>
    /// 監聽回撥
    /// </summary>
    /// <param name="ar"></param>
    public static void AcceptCallback(IAsyncResult ar)
    {
        // 標記主執行緒繼續執行  
        allDone.Set();

        // 獲取socket來處理client請求  
        Socket listener = (Socket)ar.AsyncState;
        Socket handler = listener.EndAccept(ar);     

        // 建立資料物件(儲存接收資料)
        StateObject state = new StateObject();
        state.workSocket = handler;
        ClientSockets.Add(handler);
        Console.WriteLine(ClientSockets.Count);
        // 處理傳遞進來的資料
        handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
            new AsyncCallback(ReadCallback), state);
    }

    /// <summary>
    /// 讀取客戶端請求資料回撥
    /// </summary>
    /// <param name="ar"></param>
    public static void ReadCallback(IAsyncResult ar)
    {
        String content = String.Empty;

        // Retrieve the state object and the handler socket  
        // from the asynchronous state object.  
        // 在read回撥函式中呼叫 IAsyncResult(ar) 的 AsyncState 方法,以獲取傳遞給 BeginReceive 方法的狀態物件
        // 此時就已經獲取到客戶端請求的資料,儲存在state.buffer中,如果此時還有資料進來也不會填充state的buffer,而是等待下一次回撥被呼叫
        StateObject state = (StateObject)ar.AsyncState;
        // 從此狀態物件中提取接收 Socket
        Socket handler = state.workSocket;


        // Read data from the client socket.
        // 獲取 Client Socket後,可以呼叫 EndReceive 方法成功完成(關閉) BeginReceive 方法中啟動的非同步讀取操作,並返回所讀取的位元組數      
        int bytesRead = handler.EndReceive(ar);

        if (bytesRead > 0)
        {
            // There  might be more data, so store the data received so far.
            // 可能會有很多資料要接收,暫存當前已經接收到的資料,StateObject.buffer在ar.AsyncState的時候就已經被填充(實測)
            state.sb.Clear();
            state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));

            // Check for end-of-file tag. If it is not there, read
            // more data. 
            // 檢查end-of-file,如果沒喲檢測到就再繼續讀。
            content = state.sb.ToString();
            Console.WriteLine(content);
            /*
            if (content.IndexOf("<EOF>") > -1)
            {
                // All the data has been read from the
                // client. Display it on the console.  
                Console.WriteLine("Read {0} bytes from socket. \n Data : {1}",
                    content.Length, content);
                // Echo the data back to the client.  
                Send(handler, content);
            }
            else
            {
                // Not all data received. Get more.  
                // 沒有讀取到所有資料,繼續讀取,這裡是個遞迴
                handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                new AsyncCallback(ReadCallback), state);
            }*/
            handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                new AsyncCallback(ReadCallback), state);
        }
    }

    private static void Send(Socket handler, String data)
    {
        // Convert the string data to byte data using ASCII encoding.  
        // 轉換string到位元組陣列。使用ASCII編碼
        byte[] byteData = Encoding.ASCII.GetBytes(data);

        // Begin sending the data to the remote device. 
        // 開始傳送,非同步傳送
        // 這裡的handler是客戶端client請求來的
        handler.BeginSend(byteData, 0, byteData.Length, 0,
            new AsyncCallback(SendCallback), handler);
    }

    /// <summary>
    /// 傳送回撥,傳送什麼如何傳送在這裡實現
    /// </summary>
    /// <param name="ar"></param>
    private static void SendCallback(IAsyncResult ar)
    {
        try
        {
            // Retrieve the socket from the state object
            // 獲取socket ,ar.AsyncState返回的是個object型別,可以轉為state也可以轉為socket
            Socket handler = (Socket)ar.AsyncState;

            // Complete sending the data to the remote device. 
            // 在回撥方法中,呼叫 IAsyncResult 引數的 AsyncState 方法以獲取傳送 Socket。 
            // 獲取 Socket後,可以呼叫 EndSend 方法成功完成傳送操作,並返回傳送的位元組數。
            int bytesSent = handler.EndSend(ar);
            //Console.WriteLine("Sent {0} bytes to client.", bytesSent);

            //handler.Shutdown(SocketShutdown.Both);
            //handler.Close();
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    public static int Main(String[] args)
    {
        StartListening();
        return 0;
    }
}