2017-04-24 113 views
1

有两个程序,我做了没有工作。有服务器和客户端。服务器通过给用户一个ID(从0开始)接受许多客户端。服务器根据服务器的标识将命令发送到特定的客户端。 (例如:200个客户端连接到1个服务器,服务器的选择ID是'5',所以服务器将把命令发送到所有的客户端,并且客户端会询问服务器他想要执行他的命令的ID,如果它是'5',则该客户端将执行并将数据发送到服务器)。 客户端有很多命令,但是为了创建具有相同错误的最小代码,我只使用1个命令(dir)。基本上,服务器将命令发送给客户端,如果它与客户端当前ID和服务器当前ID匹配,它将处理该命令。默认情况下,服务器的当前编号为10以下是命令的列表,以帮助谁愿意回答人:C#套接字:客户端错误地处理'a'作为客户端ID

服务器命令:

  • 列表(显示所有用户ID的连接和服务器的当前ID) - >在服务器上发生的情况

  • 目录(请求的客户端发送它的目录列表) - >客户端发送,由服务器读取

  • 集(设置服务器的当前id来任意数量)(例如: '设置4')

客户:

using System; 
using System.Speech.Synthesis; 
using System.Windows.Forms; 
using System.IO; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using System.Net.Sockets; 
using System.Net; 
namespace clientControl 
{ 
    class Program 
    { 
     public static string directory = @"C:\"; 
     public static int id = -10; 
     public static Socket sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
     static void Main(string[] args) 
     { 
      Connect(); 
      getSession(); 
      ReadResponse(sck); 
     } 
     static byte[] readResponseFunc() 
     { 
      long fileSize = 0; 
      string fileSizeInString = null; 
      byte[] fileSizeInByteArray = new byte[1024]; 
      int fileSizeLength = sck.Receive(fileSizeInByteArray); 
      for (int i = 0; i < fileSizeLength; i++) 
      { 
       fileSizeInString = fileSizeInString + (char)fileSizeInByteArray[i]; 
      } 
      try 
      { 
       fileSize = Convert.ToInt64(fileSizeInString); 
      } 
      catch { Console.WriteLine(fileSizeInString); } 
      sck.Send(Encoding.ASCII.GetBytes("a")); 

      byte[] responseUnknown = new byte[1]; 
      sck.Receive(responseUnknown); 
      if (Encoding.ASCII.GetString(responseUnknown) == "b") 
      { 
       byte[] dataInByteArray = new byte[fileSize]; 
       int dataLength = sck.Receive(dataInByteArray); 
       return dataInByteArray; 
      } 
      return Encoding.ASCII.GetBytes("ERROR RESPONSE FUNC"); 
     } 
     static void getSession() 
     { 
      byte[] message_1 = Encoding.ASCII.GetBytes("make_id"); 
      sck.Send(Encoding.ASCII.GetBytes(message_1.Length.ToString())); 
      byte[] responseUnknown = new byte[1]; 
      if (Encoding.ASCII.GetString(responseUnknown) == "a") 
      { 
       sck.Send(Encoding.ASCII.GetBytes("b")); 
       sck.Send(message_1); 
      } 
      byte[] receivedID = readResponseFunc(); 
      id = Convert.ToInt32(Encoding.ASCII.GetString(receivedID)); 
     } 
     static bool SocketConnected(Socket s) 
     { 
      bool part1 = s.Poll(1000, SelectMode.SelectRead); 
      bool part2 = (s.Available == 0); 
      if (part1 && part2) 
       return false; 
      else 
       return true; 
     } 
     static void ReadResponse(Socket sck) 
     { 
      while (true) 
      { 

       if (SocketConnected(sck) == true) 
       { 
        try 
        { 
         string response = Encoding.ASCII.GetString(readResponseFunc()); 

         byte[] message_1 = Encoding.ASCII.GetBytes("get_id"); 
         sck.Send(Encoding.ASCII.GetBytes(message_1.Length.ToString())); 
         byte[] responseUnknown = new byte[1]; 
         if (Encoding.ASCII.GetString(responseUnknown) == "a") 
         { 
          sck.Send(Encoding.ASCII.GetBytes("b")); 
          sck.Send(message_1); 
         } 
         byte[] response_2InByteArray = readResponseFunc(); 
         string response_2 = Encoding.ASCII.GetString(response_2InByteArray); 
         if (Convert.ToInt32(response_2) == id) 
         { 
          if (response == "dir") 
          { 
           string resultOfDirring = "Current Directory: " + directory + "\n\n"; 
           string[] folderListingArray = Directory.GetDirectories(directory); 
           foreach (string dir in folderListingArray) 
           { 
            string formed = "DIRECTORY: " + Path.GetFileName(dir); 
            resultOfDirring = resultOfDirring + formed + Environment.NewLine; 
           } 
           string[] fileListingArray = Directory.GetFiles(directory); 
           foreach (var file in fileListingArray) 
           { 
            FileInfo fileInfo = new FileInfo(file); 
            string formed = "FILE: " + Path.GetFileName(file) + " - FILE SIZE: " + fileInfo.Length + " BYTES"; 
            resultOfDirring = resultOfDirring + formed + Environment.NewLine; 
           } 
           byte[] message_11 = Encoding.ASCII.GetBytes(resultOfDirring); 
           sck.Send(Encoding.ASCII.GetBytes(message_11.Length.ToString())); 
           byte[] responseUnknown_11 = new byte[1]; 
           if (Encoding.ASCII.GetString(responseUnknown_11) == "a") 
           { 
            sck.Send(Encoding.ASCII.GetBytes("b")); 
            sck.Send(message_11); 
           } 
          } 
         } 
         else { } 
        } 
        catch { if (SocketConnected(sck) == false) { Console.WriteLine("Client Disconnected: " + sck.RemoteEndPoint); break; }; } 
       } 
       else if (SocketConnected(sck) == false) { Console.WriteLine("Client Disconnected: " + sck.RemoteEndPoint); break; } 
      } 
     } 
     static void Connect() 
     { 
      while (true) 
      { 
       try 
       { 
        sck.Connect(IPAddress.Parse("127.0.0.1"), 80); 
        break; 
       } 
       catch { } 
      } 
     } 
    } 
} 

服务器:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Net; 
using System.Net.Sockets; 
using System.IO; 
using System.Text; 
using System.Threading; 

namespace serverControl 
{ 
    class Program 
    { 
     public static int ftpNum = 1; 
     public static List<int> listOfClient = new List<int>(); 
     public static TcpListener server = new TcpListener(IPAddress.Parse("127.0.0.1"), 80); 
     public static string message = null; 
     public static int id = 0; 
     public static int selected_id = 10; 
     static void Main(string[] args) 
     { 
      server.Start(); 
      Thread startHandlingClientThread = new Thread(startHandlingClient); 
      startHandlingClientThread.Start(); 
      while (true) 
      { 
       Console.Write(":> "); 
       string rawmessage = Console.ReadLine(); 
       if (rawmessage == "list") 
       { 
        Console.WriteLine("SELECTED ID: " + selected_id); 
        Console.WriteLine("List of Clients ID:"); 
        for (int i = 0; i < listOfClient.Count; i++) 
        { 
         Console.WriteLine(listOfClient[i]); 
        } 
        message = rawmessage+"PREVENT_REPETITION_IN_COMMAND"; 
       } 
       else if (rawmessage.Contains("set ")) { int wantedChangeId = Convert.ToInt32(rawmessage.Replace("set ", "")); selected_id = wantedChangeId; message = rawmessage+ "PREVENT_REPETITION_IN_COMMAND"; } 
       else 
       { 
        message = rawmessage; 
       } 
      } 
     } 

     static byte[] readResponseFunc(Socket sck) 
     { 
      long fileSize = 0; 
      string fileSizeInString = null; 
      byte[] fileSizeInByteArray = new byte[1024]; 
      int fileSizeLength = sck.Receive(fileSizeInByteArray); 
      for (int i = 0; i < fileSizeLength; i++) 
      { 
       fileSizeInString = fileSizeInString + (char)fileSizeInByteArray[i]; 
      } 
      fileSize = Convert.ToInt64(fileSizeInString); 

      sck.Send(Encoding.ASCII.GetBytes("a")); 

      byte[] responseUnknown = new byte[1]; 
      sck.Receive(responseUnknown); 
      if (Encoding.ASCII.GetString(responseUnknown) == "b") 
      { 
       byte[] dataInByteArray = new byte[fileSize]; 
       int dataLength = sck.Receive(dataInByteArray); 
       return dataInByteArray; 
      } 
      return Encoding.ASCII.GetBytes("ERROR RESPONSE FUNC"); 
     } 
     static void startHandlingClient() 
     { 
      while (true) 
      { 
       handleClient(server); 
      } 
     } 
     static void handleClient(TcpListener clientToAccept) 
     { 
      Socket sck = clientToAccept.AcceptSocket(); 
      Thread myNewThread = new Thread(() => ReadResponse(sck)); 
      myNewThread.Start(); 
     } 
      static bool SocketConnected(Socket s) 
      { 
       bool part1 = s.Poll(1000, SelectMode.SelectRead); 
       bool part2 = (s.Available == 0); 
       if (part1 && part2) 
        return false; 
       else 
        return true; 
      } 
     static void ReadResponse(Socket sck) 
     { 
      Thread myNewThread = new Thread(() => SendtoClient(sck)); 
      myNewThread.Start(); 
      Thread.Sleep(2000); 
      while (true) 
      { 

       if (SocketConnected(sck) == true) 
       { 
        try 
        { 
         byte[] dataInByteArray = readResponseFunc(sck); 

         string response = Encoding.ASCII.GetString(dataInByteArray); 
         Console.WriteLine("res: " + response); 
         if (response != "make_id" && response != "get_id") { Console.WriteLine(response); } 
         if (response == "make_id") 
         { 
          Console.WriteLine("Someone wants an ID"); 
          byte[] message_1 = Encoding.ASCII.GetBytes(id.ToString()); 
          listOfClient.Add(id); 
          // START 
          sck.Send(Encoding.ASCII.GetBytes(message_1.Length.ToString())); 
          byte[] responseUnknown = new byte[1]; 
          if (Encoding.ASCII.GetString(responseUnknown) == "a") 
          { 
           sck.Send(Encoding.ASCII.GetBytes("b")); 
           sck.Send(message_1); 
          } 
          id++; 
         } 
         if (response == "get_id") 
         { 
          byte[] message_1 = Encoding.ASCII.GetBytes(selected_id.ToString()); 
          sck.Send(Encoding.ASCII.GetBytes(message_1.Length.ToString())); 
          byte[] responseUnknown = new byte[1]; 
          if (Encoding.ASCII.GetString(responseUnknown) == "a") 
          { 
           sck.Send(Encoding.ASCII.GetBytes("b")); 
           sck.Send(message_1); 
          } 
         } 
        } 
        catch { if (SocketConnected(sck) == false) { Console.WriteLine("Client Disconnected: " + sck.RemoteEndPoint); break; }; } 
       } 
       else if (SocketConnected(sck) == false) { Console.WriteLine("Client Disconnected: " + sck.RemoteEndPoint); break; } 
      } 
     } 
     static void SendtoClient(Socket sck) 
     { 
      string tempmessage = null; 
      while (true) 
      { 
       if (SocketConnected(sck) == true) 
       { 
        if (tempmessage != message) 
        { 
         if (!message.Contains("PREVENT_REPETITION_IN_COMMAND")) 
         { 
          byte[] message_1 = Encoding.ASCII.GetBytes(message); 
          sck.Send(Encoding.ASCII.GetBytes(message_1.Length.ToString())); 
          byte[] responseUnknown = new byte[1]; 
          if (Encoding.ASCII.GetString(responseUnknown) == "a") 
          { 
           sck.Send(Encoding.ASCII.GetBytes("b")); 
           sck.Send(message_1); 
          } 
         } 
         tempmessage = message; 
        } 
       } 
       else if (SocketConnected(sck) == false) 
       { Console.WriteLine("Client Disconnected: " + sck.RemoteEndPoint); break; } 
      } 
     } 
    } 
} 

问题: 问题是内GetSession或ReadResponseFunc函数。客户端认为他的服务器收到的ID是'a'(假设是一个整数)。我不想要一个解决方案,建议我使用其他库或 TcpClient类

赏金:

我提出了一个赏金没有到期时间那些谁解决问题。

+0

使用'Socket'作为参考的示例:http://stackoverflow.com/questions/34586733/sending-a-value-from-server-to-client-with-sockets/34669446#34669446 – Ian

回答

4

你的代码中的逻辑非常混乱。我对你的问题:你为什么要在服务器和客户端之间来回发送'a'和'b'?是否收到该消息的某种确认?

不管怎么说,在整个快速测试我刚才已经做了,看来这个问题是您的服务器的59线:

sck.Send(Encoding.ASCII.GetBytes("a")); 

这是我在测试过程中想通了:

  1. 服务器执行。
  2. 客户端执行。
  3. 客户端向服务器发送“make_id”(客户端51行)的长度
  4. 客户端等待响应返回。
  5. 服务器读取值,并发送回“A”(服务器的59号线)

您可能需要花一些时间来理顺你的协议,这是减少混乱和更有条理。这会帮助像我这样的人,并且更容易发现错误。

+0

我同意你的分析。我也同意你的建议,即OP需要重新设计代码并创建一个合适的更高级别的协议:我建议在0x02(STX)和0x03(ETX)之间封装消息,和/或在消息的长度开始。还使用定义的消息结构(报头),例如包含消息ID或类似内容的字节0和1。 –

+0

我必须发送文件长度和文件。这是我添加发送'a'和'b'部分之前发送的代码: - sck.Send(encoding.ascii.getbytbytes(data.Length))和下一行sck.send(data);.但服务器认为数据发送被打包为1(收到的消息是:4dir)。所以我创建了程序发送'a'和'b',所以它不会与其他响应混合。 – Adola

+0

我已经调试并发现问题:'服务器读取值并返回''(服务器的第59行)',就像你提到的一样。但是,我仍然无法解决问题......您可以编辑或至少告诉我为什么发送'a'。 – Adola

1

用户'Bobby'已经发现你的问题。信用去给他。

我进一步建议您使用较少的线程,因为线程同步需要一定的努力,正确的做法是:从不同线程访问的所有数据都必须通过锁保护,以便不会在CPU高速缓存中保留过时的值。从该线程的“线程同步原语”中使用.net Monitor

关于线程本身:
您应该只有一个线程在服务器中。此线程从列表中获取所有客户端(由Monitor保护),在收到连接尝试时添加它们。在每个客户端上,它会检查传入消息,评估它们并根据需要回复自己的消息。

客户端也只有一个线程,它会循环(不要忘记循环中的睡眠,否则将有100%使用CPU内核),在需要时发送消息并等待消息发送时的回复。

关于讯息:
我已经在Bobby的回答的评论中提出了一些建议。我建议你创建一个CMessage类,该类有一个Serialize()和Deserialze()来创建一个从CMessage成员发送的字节数组(序列化内容),反之亦然,从接收到的字节中填充成员。然后你可以在这两个程序中使用这个类,并且你将有共同的解决方案。

+0

谢谢!我会记住这一点。 – Adola