none
使用Socket交換資料.Server端要如何取得Client端IP? RRS feed

  • 問題

  • 下面是我參考的程式
    Server端:
    using System;
    using System.Text;
    using System.Net;
    using System.Net.Sockets;
    using System.Threading;  

    namespace SocketServer
    {
     class Class1
     {
      [STAThread]
      static void Main(string[] args)
      {
          Socket udpServer = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.IP);
          IPEndPoint server = new IPEndPoint(IPAddress.Any, 6000);

          udpServer.Bind(server);

          Console.WriteLine("Server:");
          while (true)
          {
              byte[] buff = new byte[20];
              udpServer.Receive(buff);
              string s = Encoding.ASCII.GetString(buff, 0, buff.Length);
              Console.WriteLine(s);
          }
      }
     }
    }
    Client端
    using System;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;

    namespace SocketClient
    {
        class Class1
        {
            [STAThread]
            static void Main(string[] args)
            {   
                
                IPEndPoint server = new IPEndPoint(IPAddress.Parse("140.138.154.202"), 6000);
                UdpClient local = new UdpClient();
                local.Connect(server);

                Console.WriteLine("Client:");
                while (true)
                {
                    string s = Console.ReadLine();
                    byte[] data = Encoding.ASCII.GetBytes(s);
                    local.Send(data, data.Length);
                }
            }
        }
    }
    Server端IP是固定的.Client端IP則不一定

    目前程式的功能還停在Client端傳給Server端資料時.Server端會將接收到的字串顯示在螢幕上.
    我希望能夠把程式改成當Server端接收到字串時.能回傳一個字串給Client.
    但是不知道在SERVER端該如何去取得CLIENT端的IP.
    請問我該怎麼做?

    有使用SOCKET交換資料的範例可以參考嗎?

    2009年7月15日 上午 09:11

解答

  • 1. 通常在UPD的狀態, 習慣性會用ProtocolType.Udp 而不是 ProtocolType.IP
    Socket udpServer = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp );

    2. Connect 這個東西在Udp上的效用不大 , 因為它是無連結式的

    3.你如果要抓到遠端的IP , 首先要以[IPEndPoint 建構函式 (IPAddress, Int32) ]建立一個 IPEndPoint執行個體 ,傳入參數為 (IpAddress.Any ,0) , 假設這個叫 RemoteEndPoint好了.
     然後Socket.Receive(bytes[])要改為使用 [Socket.ReceiveFrom 方法 (Byte[] , EndPoint) ]
    把 RemoteEndPoint執行個體傳入Sokect.ReceiveForm方法的  EndPoint參數 .
    之後就可以用 RemoteEndPoint.Address.ToString()取得IP位址
    請關心自己的問題,不要問了就放空;這是對別人與自己的尊重
    2009年7月16日 上午 03:58
    版主

所有回覆

  • 你有去抓 Socket.RemoteEndPoint 這個屬性嗎?
    小人物一枚。
    2009年7月15日 上午 09:21
    版主
  • 我有試過在SERVER端程式中
    udpServer.Receive(buff);
    底下加上
    IPEndPoint ClientIP = (IPEndPoint)udpServer.RemoteEndPoint;
    試圖擷取client端的IP.
    不過當程式執行到這一行時會出現
    "不允許傳送或接收資料的要求,因為通訊端並未連線,而且 (在資料包通訊端使用 sendto 呼叫進行傳送時) 並未提供位址。"
    的錯誤訊息.

    請問在SERVER端要怎麼去使用Socket.RemoteEndPoint這個屬性來抓取Client的IP?
    2009年7月15日 上午 09:32
  • 1. 通常在UPD的狀態, 習慣性會用ProtocolType.Udp 而不是 ProtocolType.IP
    Socket udpServer = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp );

    2. Connect 這個東西在Udp上的效用不大 , 因為它是無連結式的

    3.你如果要抓到遠端的IP , 首先要以[IPEndPoint 建構函式 (IPAddress, Int32) ]建立一個 IPEndPoint執行個體 ,傳入參數為 (IpAddress.Any ,0) , 假設這個叫 RemoteEndPoint好了.
     然後Socket.Receive(bytes[])要改為使用 [Socket.ReceiveFrom 方法 (Byte[] , EndPoint) ]
    把 RemoteEndPoint執行個體傳入Sokect.ReceiveForm方法的  EndPoint參數 .
    之後就可以用 RemoteEndPoint.Address.ToString()取得IP位址
    請關心自己的問題,不要問了就放空;這是對別人與自己的尊重
    2009年7月16日 上午 03:58
    版主
  • 感謝Bill的解答.我已經可以抓取Client的IP了
    下面是我修改過後的程式
    SERVER:
    using System;
    using System.Text;
    using System.Net;
    using System.Net.Sockets;
    using System.Threading;  

    namespace SocketServer
    {
     class Class1
     {
      [STAThread]
      static void Main(string[] args)
      {
          Socket udpServer = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
          IPEndPoint server = new IPEndPoint(IPAddress.Any, 6000);

          udpServer.Bind(server);

          Console.WriteLine("Server:");
          while (true)
          {
              byte[] buff = new byte[20];
              IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
              EndPoint senderRemote = (EndPoint)sender;
              udpServer.ReceiveFrom(buff, ref senderRemote);
              string s = Encoding.ASCII.GetString(buff, 0, buff.Length);
              Console.WriteLine(s);
          }
      }
     }
    }
    我還有幾個疑問..
    1.在Client端時我設定的PORT應該是6000.但是senderRemote 抓到的PORT是1207.不過IP是正確的
    2.為什麼要刻意先宣告一個IPEndPoint 再指給EndPoint呢? 這兩種宣告的關係是? 
    3.宣告成IPEndPoint的RemoteEndPoint要怎麼傳入Sokect.ReceiveForm方法的  EndPoint參數 .兩個型態不同吧?
    我現在是將senderRemote 轉成字串後再將IP分離出來.有更加簡潔的做法嗎?



    2009年7月16日 上午 04:48
  • 1.你發送端是這樣宣告的  UdpClient local = new UdpClient(); <==這代表系統自行選擇 Port號
    2. 先來看MSDN文是怎麼解釋這一個多載的 詳情請參閱 MSDN文件庫 [Socket. ReceiveFrom 方法 (Byte[] , EndPoint) ]
    Socket. ReceiveFrom 方法 (Byte[] , EndPoint)

    接收資料包至資料緩衝區中,並儲存端點。

    因為我們不知道會是哪個IP跟Port從遠端傳來 (這點和Tcp 不同, 因Tcp會做Accept) , 所以先以 IPEndPoint(IPAddress.Any, 0)來宣告一個IPEndPoint  ( IPEndPoint 基本上是繼承EndPoint而來)
    當Udp接收時, 它就會將遠端的相關ip與port資料存入這一個 RemoteIpEndpoint , 所以就可以取出其Address與Port

    3. IPEndPoint 基本上是繼承EndPoint而來 , 至於為何不用 EndPoint宣告 ? 因為EndPoint是 abstract 類別 , 這種類別只能當基底類別使用, 不能產生執行個體 , 如果有這個疑問你可以先查查 MSDN文件庫的相關說明.

    4. IPEndPoint類別有三個屬性 , 請參考下方連結的說明.

    請參閱MSDN 文件庫
    [EndPoint 類別 ]
    [IPEndPoint 類別 ]

    另外, 我在點部落上有幾篇相關文章, 你也可以參考一下:
    [.NET Socket TCP/UDP程式入門基礎《建構Socket執行個體》 ]
    [.NET Socket TCP/UDP程式入門基礎《IPEndPoint類別》 ]
    [.NET Socket TCP/UDP程式入門基礎《IPAddress類別》 ]
    [實作同步 .NET Socket UDP《使用UdpClient類別 》]

    請關心自己的問題,不要問了就放空;這是對別人與自己的尊重
    2009年7月16日 上午 09:00
    版主
  • 感謝指教!
    2009年7月22日 上午 05:34
  • 我的作法是
    UdpClient oUDPClient = new UdpClient();
    IPEndPoint endPoint4Receiving = new IPEndPoint(IPAddress.Any, 0);
    //監聽&接收資料
    String rcvMsg = Encoding.Default.GetString(oUDPClient.Receive(ref endPoint4Receiving));
    //這就是發送資料(遠端)的IP
    endPoint4Receiving.Address
    //這就是發送資料(遠端)的Port
    endPoint4Receiving.Port
    
    這應該簡單了些
    2009年7月22日 下午 07:33