2016-09-26 191 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个字节,或其他。您必须循环接收,直到您收到所有消息。这意味着你必须知道你什么时候阅读过。要么最后需要有一个标题或一些哨兵。