我正在尝试制作一个简单的服务器应用程序,以学习c#中的多线程服务器编程的基础知识。基本思想很简单:客户端连接到服务器并发送:“获取时间”以接收服务器的当前时间。所有tcplistener线程和套接字都应在单独的线程上运行。我不知道为什么,但是当应用程序完成所有线程的初始化时,控制台应用程序将关闭。
这是服务器代码:
class Program
{
static public int minPort;
static public int maxPort;
static int openPort = 0;
static byte[] sendData = new byte[1024];
static TcpListener[] listeners;
static Thread[] connectionThreads;
static void Main()
{
Console.Write("What do you want your minimum port to be? ");
minPort = Convert.ToInt32(Console.ReadLine());
Console.Write("What do you want your maximum port to be? ");
maxPort = Convert.ToInt32(Console.ReadLine());
//init
ThreadStart streamThreadStart = new ThreadStart(DataStream);
openPort = maxPort - minPort;
listeners = new TcpListener[maxPort - minPort];
connectionThreads = new Thread[maxPort - minPort];
for (int i = 0; i == maxPort - minPort; i++)
{
listeners[i] = new TcpListener(IPAddress.Any, minPort + i);
connectionThreads[i] = new Thread(streamThreadStart);
Thread.Sleep(10);
openPort = openPort + 1;
}
}
static void DataStream()
{
int port = openPort;
byte[] receiveData = new byte[1024];
listeners[openPort].Start();
Socket socket = listeners[port].AcceptSocket();
NetworkStream stream = new NetworkStream(socket);
while (true)
{
socket.Receive(receiveData);
Console.WriteLine("Received: " + BitConverter.ToString(receiveData));
socket.Send(parseCommand(receiveData));
}
}
static byte[] parseCommand(byte[] input)
{
string RCommand = BitConverter.ToString(input);
string SCommand;
if (RCommand == "get time")
{
SCommand = DateTime.Now.ToUniversalTime().ToString();
}else
{
SCommand = "Unknown Command, please try again";
}
byte[] output = Encoding.ASCII.GetBytes(SCommand);
return output;
}
}
答案 0 :(得分:0)
通常,最佳实践是控制台应用程序在用户想要停止应用程序时提供“输入任何键以退出”提示。但是您始终可以查询要退出的特定按键,例如“ q”。
以下是一些入门代码:
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
答案 1 :(得分:0)
退出前,您需要join个线程。
static public void Main()
{
/*
Existing code goes here
*/
//Before exiting, make sure all child threads are finished
foreach (var thread in connectionThreads) thread.Join();
}
当您的程序调用Thread.Join时,它告诉操作系统在子线程完成之前,不需要为任何时间片安排主线程。与其他技术(例如,忙等待(即运行while
循环))相比,它的重量更轻。虽然主线程仍会占用资源,但不会占用任何CPU时间。
另请参阅When would I use Thread.Join?和c# Waiting for multiple threads to finish
答案 2 :(得分:0)
您的代码不会启动新线程! 因此,我对您的代码进行了一些更改:
class Program
{
static public int minPort;
static public int maxPort;
//static int openPort = 0;
static byte[] sendData = new byte[1024];
static TcpListener[] listeners;
static Thread[] connectionThreads;
static void Main()
{
Console.Write("What do you want your minimum port to be? ");
minPort = Convert.ToInt32(Console.ReadLine());
Console.Write("What do you want your maximum port to be? ");
maxPort = Convert.ToInt32(Console.ReadLine());
//init
// ThreadStart streamThreadStart = new ThreadStart(DataStream(0));
//openPort = minPort;
listeners = new TcpListener[maxPort - minPort];
connectionThreads = new Thread[maxPort - minPort];
//for (int i = 0; i == maxPort - minPort; i++) it can't work
for (int i = 0; i < maxPort - minPort; i++)
{
listeners[i] = new TcpListener(IPAddress.Any, minPort + i);
connectionThreads[i] = new Thread(new ParameterizedThreadStart(DataStream)); //thread with start parameter
connectionThreads[i].Start(i); // start thread with index
Thread.Sleep(10);
}
}
static void DataStream(object o)
{
int index = (int)o; //get index
byte[] receiveData = new byte[1024];
listeners[index].Start(); // start listener with right index
Socket socket = listeners[index].AcceptSocket();
NetworkStream stream = new NetworkStream(socket);
while (true)
{
socket.Receive(receiveData);
Console.WriteLine("Received: " + BitConverter.ToString(receiveData));
socket.Send(parseCommand(receiveData));
}
}
static byte[] parseCommand(byte[] input)
{
string RCommand = BitConverter.ToString(input);
string SCommand;
if (RCommand == "get time")
{
SCommand = DateTime.Now.ToUniversalTime().ToString();
}
else
{
SCommand = "Unknown Command, please try again";
}
byte[] output = Encoding.ASCII.GetBytes(SCommand);
return output;
}
}