【发布时间】:2016-05-16 01:41:20
【问题描述】:
我正在 TCP 之上编写一个网络层,我在 UnitTest 阶段遇到了一些麻烦。
这是我正在做的(我的库由多个类组成,但我只向您展示导致我的问题的本机指令,以限制帖子的大小):
private const int SERVER_PORT = 15000;
private const int CLIENT_PORT = 16000;
private const string LOCALHOST = "127.0.0.1";
private TcpClient Client { get; set; }
private TcpListener ServerListener { get; set; }
private TcpClient Server { get; set; }
[TestInitialize]
public void MyTestInitialize()
{
this.ServerListener = new TcpListener(new IPEndPoint(IPAddress.Parse(LOCALHOST), SERVER_PORT));
this.Client = new TcpClient(new IPEndPoint(IPAddress.Parse(LOCALHOST), CLIENT_PORT));
this.ServerListener.Start();
}
// In this method, I just try to connect to the server
[TestMethod]
public void TestConnect1()
{
var connectionRequest = this.ServerListener.AcceptTcpClientAsync();
this.Client.Connect(LOCALHOST, SERVER_PORT);
connectionRequest.Wait();
this.Server = connectionRequest.Result;
}
// In this method, I assume there is an applicative error within the client and it is disposed
[TestMethod]
public void TestConnect2()
{
var connectionRequest = this.ServerListener.AcceptTcpClientAsync();
this.Client.Connect(LOCALHOST, SERVER_PORT);
connectionRequest.Wait();
this.Server = connectionRequest.Result;
this.Client.Dispose();
}
[TestCleanup]
public void MyTestCleanup()
{
this.ServerListener?.Stop();
this.Server?.Dispose();
this.Client?.Dispose();
}
首先,如果我想更早地从同一端点连接到同一端口上的服务器,我必须首先处理服务器:
如果你像这样运行我的测试,它会在第一次成功运行。
第二次,在两个测试中,它都会在 Connect 方法上抛出一个异常,认为端口已经在使用中。
我发现避免这种异常的唯一方法(并且能够从同一个端点连接到同一个侦听器)是通过向已处理的客户端发送字节两次(在第一次发送时,没有问题,只有在第二次发送时才抛出异常。
如果我引发异常,我什至不需要 Dispose Server ...
为什么Server.Dispose() 没有关闭连接并释放端口???有没有比引发异常更好的方法来释放端口?
提前致谢。
(对不起我的英语,我不是母语)
这是一个主函数中的示例,更容易结帐:
private const int SERVER_PORT = 15000;
private const int CLIENT_PORT = 16000;
private const string LOCALHOST = "127.0.0.1";
static void Main(string[] args)
{
var serverListener = new TcpListener(new IPEndPoint(IPAddress.Parse(LOCALHOST), SERVER_PORT));
var client = new TcpClient(new IPEndPoint(IPAddress.Parse(LOCALHOST), CLIENT_PORT));
serverListener.Start();
var connectionRequest = client.ConnectAsync(LOCALHOST, SERVER_PORT);
var server = serverListener.AcceptTcpClient();
connectionRequest.Wait();
// Oops, something wrong append (wrong password for exemple), the client has to be disposed (I really want this behavior)
client.Dispose();
// Uncomment this to see the magic happens
//try
//{
//server.Client.Send(Encoding.ASCII.GetBytes("no problem"));
//server.Client.Send(Encoding.ASCII.GetBytes("oops looks like the client is disconnected"));
//}
//catch (Exception)
//{ }
// Lets try again, with a new password for example (as I said, I really want to close the connection in the first place, and I need to keep the same client EndPoint !)
client = new TcpClient(new IPEndPoint(IPAddress.Parse(LOCALHOST), CLIENT_PORT));
connectionRequest = client.ConnectAsync(LOCALHOST, SERVER_PORT);
// If the previous try/catch is commented, you will stay stuck here,
// because the ConnectAsync has thrown an exception that will be raised only during the Wait() instruction
server = serverListener.AcceptTcpClient();
connectionRequest.Wait();
Console.WriteLine("press a key");
Console.ReadKey();
}
如果触发错误并且程序拒绝让您连接,您可能需要重新启动 Visual Studio(或等待一段时间)。
【问题讨论】:
-
您似乎正在测试 .NET 的
TcpClient和TcpListener。你应该测试你自己的代码,而不是框架的。 -
正如我所说,我正在 Tcp 之上编写一个网络层。但我只给你看那些给我带来麻烦的指示。我不会在我的整个封装代码中向您展示它们,以免淹没您。我将编辑我的介绍,使其更加明确!