2016-09-26 186 views
0

我正在啓動套接字程序,並且正在設置服務器和兩種類型的客戶端(請求者和仲裁者)。我正在測試連接,但他們並沒有工作。現在,我只需爲每個表單提供一個按鈕:仲裁器的「接受」按鈕和請求者的「請求」。每個按鈕都應該在另一個窗體上產生一個彈出窗口,但都不起作用。另外,我注意到當我關閉所有程序時,服務器仍然在我的進程中運行。我究竟做錯了什麼?套接字 - 不發送/接收數據

下面是服務器代碼:

namespace FPPLNotificationServer 
{ 
    class Server 
    { 

     static Socket listenerSocket; 
     static List<ClientData> _clients; 

     static void Main(string[] args) 
     { 
      Console.WriteLine("Starting server on " + Packet.GetIP4Address()); 
      listenerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
      _clients = new List<ClientData>(); 
      IPEndPoint ip = new IPEndPoint(IPAddress.Parse(Packet.GetIP4Address()), 4242); 
      listenerSocket.Bind(ip); 

      Thread listenThread = new Thread(ListenThread); 
      listenThread.Start(); 
     } 

     static void ListenThread() 
     { 
      for (;;) 
      { 
       listenerSocket.Listen(0); 
       _clients.Add(new ClientData(listenerSocket.Accept())); 
      } 
     } 

     public static void Data_IN(object cSocket) 
     { 
      Socket clientSocket = (Socket)cSocket; 

      byte[] Buffer; 
      int readBytes; 

      for (;;) 
      { 
       try 
       { 
        Buffer = new byte[clientSocket.SendBufferSize]; 
        readBytes = clientSocket.Receive(Buffer); 

        if(readBytes > 0) 
        { 
         Packet packet = new Packet(Buffer); 
         DataManager(packet); 
        } 
       }catch(SocketException ex) 
       { 
        Console.WriteLine("Client Disconnected"); 
       } 
      } 
     } 

     public static void DataManager(Packet p) 
     { 
      switch (p.packetType) 
      { 
       case Packet.PacketType.Notification: 
        foreach(ClientData c in _clients) 
        { 
         c.clientSocket.Send(p.ToBytes()); 
        } 
        break; 
      } 
     } 

    } 

    class ClientData 
    { 
     public Socket clientSocket; 
     public Thread clientThread; 
     public string id; 

     public ClientData() 
     { 
      this.id = Guid.NewGuid().ToString(); 
      clientThread = new Thread(Server.Data_IN); 
      clientThread.Start(clientSocket); 
      SendRegistrationPacket(); 
     } 

     public ClientData(Socket clientSocket) 
     { 
      this.clientSocket = clientSocket; 
      this.id = Guid.NewGuid().ToString(); 
      clientThread = new Thread(Server.Data_IN); 
      clientThread.Start(clientSocket); 
      SendRegistrationPacket(); 
     } 

     public void SendRegistrationPacket() 
     { 
      Packet p = new Packet(Packet.PacketType.Registration, "server"); 
      p.Gdata.Add(id); 
      clientSocket.Send(p.ToBytes()); 
     } 
    } 
} 

ServerData

namespace FPPLNotificationServerData 
{ 
    [Serializable] 
    public class Packet 
    { 

     public List<String> Gdata; 
     public int packetInt; 
     public bool packetBool; 
     public string senderID; 
     public PacketType packetType; 
     public string PlantName, ProductSegment, ProductCustomer; 
     public int PlantNumber; 
     public string ProductNumber, ProductAltNumber; 
     public string ProductDiscription; 
     public int ProductLine; 
     public string ProductClass, ProductLocation; 
     public int ProductMcDFactor; 

     public Packet(PacketType type, String senderID) 
     { 
      Gdata = new List<string>(); 
      this.senderID = senderID; 
      this.packetType = type; 
     } 

     public Packet(byte[] packetBytes) 
     { 
      BinaryFormatter bf = new BinaryFormatter(); 
      MemoryStream ms = new MemoryStream(packetBytes); 

      Packet p = (Packet)bf.Deserialize(ms); 
      ms.Close(); 
      this.Gdata = p.Gdata; 
      this.senderID = p.senderID; 
      this.packetType = p.packetType; 
      this.packetBool = p.packetBool; 
      this.packetInt = p.packetInt; 
     } 

     public byte[] ToBytes() 
     { 
      BinaryFormatter bf = new BinaryFormatter(); 
      MemoryStream ms = new MemoryStream(); 
      bf.Serialize(ms, this); 
      byte[] bytes = ms.ToArray(); 
      ms.Close(); 
      return bytes; 
     } 

     public static string GetIP4Address() 
     { 
      IPAddress[] ips = Dns.GetHostAddresses(Dns.GetHostName()); 
      foreach(IPAddress i in ips) 
      { 
       if(i.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) 
       { 
        return i.ToString(); 
       } 
      } 

      return "127.0.0.1"; 
     } 

     public enum PacketType 
     { 
      Registration, 
      Chat, 
      Notification, 
      Request, 
      ArbiterDecision, 
      Accept, 
      Decline 
     } 
    } 
} 

請求類:

namespace FPPLRequestClient 
{ 
    public partial class frm_Request : Form 
    { 

     public static Socket master; 
     public static string name; 
     public static string id; 
     public bool isConnected; 

     public frm_Request() 
     { 
      InitializeComponent(); 
      string IP = "127.0.0.1"; 
      master = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
      IPEndPoint ipEP = new IPEndPoint(IPAddress.Parse(IP), 4242); 
      try 
      { 
       master.Connect(ipEP); 
       isConnected = true; 

      } 
      catch (Exception) 
      { 
       isConnected = false; 
      } 

      string connectionStatus = isConnected ? "Connected" : "Disconnected"; 
      this.lbl_Status.Text = "Status: " + connectionStatus; 

      Thread t = new Thread(Data_IN); 
      t.Start(); 

     } 

     void Data_IN() 
     { 
      byte[] Buffer; 
      int readBytes; 

      while (isConnected) 
      { 
       try 
       { 
        Buffer = new byte[master.SendBufferSize]; 
        readBytes = master.Receive(Buffer); 
        if(readBytes > 0) 
        { 
         DataManager(new Packet(Buffer)); 
        } 
       }catch(SocketException ex) 
       { 
        isConnected = false; 
        this.Dispose(); 
       } 
      } 
     }//END DATA IN 

     void DataManager(Packet p) 
     { 
      switch (p.packetType) 
      { 
       case Packet.PacketType.Registration: 
        id = p.Gdata[0]; 
        break; 
       case Packet.PacketType.Accept: 
        //MessageBox.Show(p.ProductNumber); 
        this.lbl_Status.Text = p.ProductNumber + " accepted"; 
        Invalidate(); 
        break; 
      } 
     } 

     private void btn_Request_Click(object sender, EventArgs e) 
     { 
      Packet p = new Packet(Packet.PacketType.Request, id); 
      p.ProductNumber = "123456"; 
      master.Send(p.ToBytes()); 
     } 
    } 
} 

仲裁者類:

namespace FPPLArbiterClient 
{ 
    public partial class frm_Arbiter : Form 
    { 
     public static Socket master; 
     public static string name; 
     public static string id; 
     public bool isConnected; 

     public frm_Arbiter() 
     { 
      InitializeComponent(); 
      string IP = "127.0.0.1"; 
      master = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
      IPEndPoint ipEP = new IPEndPoint(IPAddress.Parse(IP), 4242); 
      try 
      { 
       master.Connect(ipEP); 
       isConnected = true; 
      } 
      catch (Exception) 
      { 
       isConnected = false; 
      } 

      string connectionStatus = isConnected ? "Connected" : "Disconnected"; 
      this.lbl_Status.Text = "Status: " + connectionStatus; 

      Thread t = new Thread(Data_IN); 
      t.Start(); 

     } 

     void Data_IN() 
     { 
      byte[] Buffer; 
      int readBytes; 

      while (isConnected) 
      { 
       try 
       { 
        Buffer = new byte[master.SendBufferSize]; 
        readBytes = master.Receive(Buffer); 
        if(readBytes > 0) 
        { 
         DataManager(new Packet(Buffer)); 
        } 
       }catch(SocketException ex) 
       { 
        isConnected = false; 
        this.Dispose(); 
       } 
      } 
     }//END DATA IN 

     void DataManager(Packet p) 
     { 
      switch (p.packetType) 
      { 
       case Packet.PacketType.Registration: 
        id = p.Gdata[0]; 
        break; 
       case Packet.PacketType.Request: 
        MessageBox.Show(p.ProductNumber + " Requested from " + p.senderID); 
        break; 
      } 
     } 

     private void btn_Accept_Click(object sender, EventArgs e) 
     { 
      MessageBox.Show("Sending acceptance of 126456"); 
      Packet p = new Packet(Packet.PacketType.Accept, id); 
      p.ProductNumber = "123456"; 
      master.Send(p.ToBytes()); 
     } 
    } 
} 

這是我第一次進入socket編程。

+0

我已將IP更改爲127.0.0.1以進行匿名 – jDave1984

回答

0

要開始您的最後一個問題,接收將阻塞,直到數據變爲可用,除非您指定超時。由於你的線程是前臺線程,這將阻止你的應用程序終止。見https://msdn.microsoft.com/en-us/library/8s4y8aff(v=vs.110).aspx。要麼使用超時,並且/或者讓線程後臺線程導致它們在關閉應用程序的主線程時終止。將創建的線程的IsBackground屬性設置爲true以實現此目的。 (另外,在上面的文章中,注意關於Shutdown的段落和Receive方法返回一個空的數組,這是你的提示,以優雅地關閉你的連接)。

TCP/IP堆棧將根據自己的判斷髮送數據(Nagle的算法),這意味着您偶爾會收到包含多個或部分消息的緩衝區。既然你的線程中有「無聲的」錯誤處理,或許你的線程由於消息被破壞而提前終止?將收到的所有內容放入緩衝區,並在將它們傳遞給消息處理程序之前,在單獨的步驟/線程中檢查完整消息的緩衝區。

這裏沒有明確的答案我很害怕,但如果檢查損壞的消息沒有幫助,請查看MSDN上的Socket示例。這可能只是你錯過的一個小細節。

0

你正在做一個基本的和常見的TCP錯誤。 TCP是一種面向字節的流媒體協議,不是面向消息的。您的接收代碼假定它讀取時收到一個Packet。這是不能保證的,你可能會收到1個字節,20個字節,或其他。您必須循環接收,直到您收到所有消息。這意味着你必須知道你什麼時候閱讀過。要麼最後需要有一個標題或一些哨兵。