在C#中,TCP服务器监听并发连接通常涉及使用多线程或异步I/O操作来处理多个客户端连接。下面是一个基本的示例,展示了如何使用TcpListener和TcpClient来创建一个简单的并发TCP服务器。
1. 创建TCP服务器
首先,你需要创建一个TcpListener实例,并指定服务器应该监听的IP地址和端口号。然后调用Start方法来开始监听传入的连接请求。
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
class TcpServer
{
static void Main()
{
TcpListener server = null;
try
{
// 设置TCP监听端口
Int32 port = 13000;
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
// 创建TcpListener实例
server = new TcpListener(localAddr, port);
// 开始监听
server.Start();
// 缓冲区用于存放接收到的数据
byte[] bytes = new byte[256];
String data = null;
Console.WriteLine("等待连接...");
// 进入监听循环
while (true)
{
// 阻塞调用,等待客户端连接
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("客户端已连接");
// 创建线程来处理客户端请求
Thread newThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
newThread.Start(client);
}
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
finally
{
// 停止监听
server.Stop();
}
Console.WriteLine("\n按下 Enter 键退出...");
Console.ReadLine();
}
// 处理客户端通信的方法
private static void HandleClientComm(object client)
{
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
byte[] message = new byte[4096];
int bytesRead;
// 接收客户端消息循环
while (true)
{
bytesRead = 0;
try
{
// 从客户端读取数据
bytesRead = clientStream.Read(message, 0, message.Length);
}
catch
{
// 客户端断开连接,退出循环
break;
}
if (bytesRead == 0)
{
// 客户端断开连接,退出循环
break;
}
// 将字节转换为ASCII字符串
ASCIIEncoding encoder = new ASCIIEncoding();
System.Text.StringBuilder builder = new System.Text.StringBuilder();
builder.Append(encoder.GetString(message, 0, bytesRead));
Console.WriteLine("收到: {0}", builder.ToString());
// 向客户端发送消息
byte[] msg = encoder.GetBytes("消息已收到");
clientStream.Write(msg, 0, msg.Length);
Console.WriteLine("发送: 消息已收到");
}
tcpClient.Close();
}
}
2. 并发处理
在上述代码中,服务器使用AcceptTcpClient方法来接受客户端连接。由于AcceptTcpClient是一个阻塞调用,当服务器等待一个客户端连接时,它不会接受其他客户端的连接。为了处理并发连接,我们创建了一个新的线程来处理每个接受的客户端连接。这样,服务器可以继续监听新的连接,而不会影响已经建立的连接。
我们使用Thread类来创建新线程,并通过ParameterizedThreadStart委托将TcpClient对象传递给HandleClientComm方法。这个方法负责读取来自客户端的数据,发送响应,并在客户端断开连接时关闭连接。
注意事项
在实际生产环境中,使用线程池(如ThreadPool类)或异步编程模型(如async和await)通常是更好的选择,因为它们可以更高效地管理资源并减少线程创建和销毁的开销。
确保正确处理异常和资源释放,以避免内存泄漏和应用程序崩溃。
考虑使用更高级的通信框架或库,如System.Net.Sockets.SocketsAsyncEventArgs或第三方库,它们可能提供更高效和灵活的并发TCP通信功能。
这个简单的示例提供了一个起点,但根据你的具体需求,你可能需要对其进行扩展和优化。