我制作了两个不起作用的程序。有服务器和客户端。服务器通过向用户提供ID(从0开始)接受许多客户端。服务器根据服务器的id向特定客户端发送命令。 (例如:200个客户端连接到1个服务器。服务器选择的id为'5',因此服务器将命令发送给所有客户端,客户端将询问服务器他想要执行命令的ID,如果它是'5',那个客户端将执行并向服务器发送数据)。 客户端有很多命令,但要创建具有相同错误的最小代码,我只使用1个命令(dir)。基本上,服务器将命令发送到客户端,如果它与客户端当前id和服务器当前id匹配,它将处理命令。默认情况下,服务器的当前ID为10.以下是帮助想要回答的人的命令列表:
服务器命令:
list(显示连接的所有用户ID和服务器的当前ID) - >发生在服务器上
dir(请求客户发送其目录列表) - >由客户端发送,由服务器读取
客户端:
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 :(得分:4)
代码中的逻辑非常混乱。我的问题:你为什么要在服务器和客户端之间来回发送'a'和'b'?是否已经收到消息的某种确认?
无论如何,在我刚刚完成的快速测试中,问题似乎是服务器的第59行:
sck.Send(Encoding.ASCII.GetBytes("a"));
这是我在测试过程中发现的:
您可能需要花一些时间来理顺您的协议,这样就不会让人感到困惑和更有条理。这将有助于像我这样的人,你更容易发现错误。
答案 1 :(得分:1)
用户&Bobby&#39;已经找到了你的问题。积分归他所有。
我进一步建议您使用更少的线程,因为线程同步在正确执行时需要付出一些努力:从不同线程访问的所有数据必须通过锁保护,以便CPU缓存中不会保留过时的值。从&#34;线程同步原语使用.net Monitor
&#34;为了那份工作。
关于线程本身:
您应该只在服务器中有一个线程。此线程从列表中获取所有客户端(由Monitor保护),在接收连接尝试时添加它们。在每个客户端上,它检查传入的消息,评估它们并在需要时回复自己的消息。
客户端也只有一个线程,它将循环(不要忘记循环中的睡眠,或者你将100%使用已使用的CPU核心),在需要时发送消息并在发送消息时等待回复。< / p>
关于消息:
我已经在回答Bobby的回答时提出了一些建议。我建议你创建一个CMessage类,它有一个Serialize()和Deserialze()来创建一个从CMessage成员发送的字节数组(序列化内容),反之亦然,从接收到的字节中填充成员。然后,您可以在两个程序中使用此类,并且您将有共同的解决方案。