C#套接字:客户端错误处理'a'作为客户的ID

时间:2017-04-24 13:47:14

标签: c# sockets tcp tcplistener

我制作了两个不起作用的程序。有服务器和客户端。服务器通过向用户提供ID(从0开始)接受许多客户端。服务器根据服务器的id向特定客户端发送命令。 (例如:200个客户端连接到1个服务器。服务器选择的id为'5',因此服务器将命令发送给所有客户端,客户端将询问服务器他想要执行命令的ID,如果它是'5',那个客户端将执行并向服务器发送数据)。 客户端有很多命令,但要创建具有相同错误的最小代码,我只使用1个命令(dir)。基本上,服务器将命令发送到客户端,如果它与客户端当前id和服务器当前id匹配,它将处理命令。默认情况下,服务器的当前ID为10.以下是帮助想要回答的人的命令列表:

服务器命令:

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

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

  • 设置(将服务器的当前ID设置为任意数字)(例如:'set 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类

奖励:

我会向那些解决问题的人提供没有到期时间的赏金。

2 个答案:

答案 0 :(得分:4)

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

无论如何,在我刚刚完成的快速测试中,问题似乎是服务器的第59行:

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

这是我在测试过程中发现的:

  1. 服务器执行。
  2. 客户执行。
  3. 客户端向服务器发送“make_id”的长度(客户端的第51行)
  4. 客户等待回复的回复。
  5. 服务器读取值并发送回'a'(服务器的第59行)
  6. 您可能需要花一些时间来理顺您的协议,这样就不会让人感到困惑和更有条理。这将有助于像我这样的人,你更容易发现错误。

答案 1 :(得分:1)

用户&Bobby&#39;已经找到了你的问题。积分归他所有。

我进一步建议您使用更少的线程,因为线程同步在正确执行时需要付出一些努力:从不同线程访问的所有数据必须通过锁保护,以便CPU缓存中不会保留过时的值。从&#34;线程同步原语使用.net Monitor&#34;为了那份工作。

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

客户端也只有一个线程,它将循环(不要忘记循环中的睡眠,或者你将100%使用已使用的CPU核心),在需要时发送消息并在发送消息时等待回复。< / p>

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