我怎样才能取消绑定在C#中的插座? [英] How can I unbind a socket in C#?

查看:87
本文介绍了我怎样才能取消绑定在C#中的插座?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些问题,重用在测试应用程序,我做了一个服务器套接字。基本上,我有一个实现同时在客户端侧和服务器侧的程序。我运行这个程序,用于测试目的的两个实例,一个实例开始举办,另一个连接。这是听力code:

I'm having some problems reusing a server socket in a test application I've made. Basically, I have a program that implements both the client side and the server side. I run two instances of this program for testing purposes, one instance starts to host and the other connects. This is the listening code:

private void Listen_Click(object sender, EventArgs e)
{
    try
    {
        server = new ConnectionWrapper();
        HideControls();
        alreadyReset = false;

        int port = int.Parse(PortHostEdit.Text);
        IPEndPoint iep = new IPEndPoint(IPAddress.Any, port);

        server.connection.Bind(iep); // bellow explanations refer to this line in particular
        server.connection.Listen(1);
        server.connection.BeginAccept(new AsyncCallback(OnClientConnected), null);
        GameStatus.Text = "Waiting for connections on port " + port.ToString();
    }
    catch (Exception ex)
    {
        DispatchError(ex);
    }
}
private void OnClientConnected(IAsyncResult iar)
{
    try
    {
        me = Player.XPlayer;
        myTurn = true;
        server.connection = server.connection.EndAccept(iar); // I will only have one client, so I don't care for the original listening socket.
        GameStatus.Text = server.connection.RemoteEndPoint.ToString() + " connected";
        StartServerReceive();
    }
    catch (Exception ex)
    {
        DispatchError(ex);
    }
}

这正常工作的第一次。然而,一段时间后(当我的小游戏结束),我称之为的Dispose()服务器对象,实施像这样的:

This works fine the first time. However, after a while (when my little game ends), I call Dispose() on the server object, implemented like this:

public void Dispose()
{
    connection.Close(); // connection is the actual socket
    commandBuff.Clear(); // this is just a StringBuilder
}

我也有这个在对象的构造函数:

I also have this in the object constructor:

public ConnectionWrapper()
{
    commandBuff = new StringBuilder();
    connection = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

    connection.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
}

我没有得到任何错误,当我点击按钮第二次。客户端连接就好了,但是我的服务器端未检测到客户端连接第二次,基本呈现服务器并没有意义。我猜它连接的是旧的,挥之不去的插座,但我不知道为什么会这样,说实话。这里的客户端连接code:

I get no error when I click the Listen button a second time. The client side connects just fine, however my server side does not detect the client connection a second time, which basically renders the server useless anyway. I'm guessing it's connecting to the old, lingering socket, but I have no idea why this is happening to be honest. Here's the client connection code:

private void Connect_Click(object sender, EventArgs e)
{
    try
    {
        client = new ConnectionWrapper();
        HideControls();
        alreadyReset = false;

        IPAddress ip = IPAddress.Parse(IPEdit.Text);
        int port = int.Parse(PortConnEdit.Text);
        IPEndPoint ipe = new IPEndPoint(ip, port);
        client.connection.BeginConnect(ipe, new AsyncCallback(OnConnectedToServer), null); 
    }
    catch (Exception ex)
    {
        DispatchError(ex);
    }
}

如果我这样做 netstat -a可在cmd中,我看到,我使用的端口仍然是约束,它的状态是 LISTENING ,即使调用的Dispose()。我看,这是正常的,而且有一个超时该端口是绑定。

If I do netstat -a in CMD, I see that the port I use is still bound and its state is LISTENING, even after calling Dispose(). I read that this is normal, and that there's a timeout for that port to be "unbound".

有没有一种方法,我可以强制将端口取消绑定或将在很短的超时时间,直到它会自动获取绑定?现在,它只是变得绑定,当我退出程序。也许我做错了什么在我的服务器?如果是的话,那会是什么?为什么客户端正常连接,但服务器端没有检测到第二次?

Is there a way I can force that port to unbind or set a very short timeout until it automatically gets unbound? Right now, it only gets unbound when I exit the program. Maybe I'm doing something wrong in my server? If so, what could that be? Why does the client connect fine, yet the server side doesn't detect it a second time?

我可以使插座总听,不处理它,并使用独立的插座来处理服务器的连接,这将可能修复它,但我想其他程序能够使用连续的游乐活动之间的端口。

I could make the socket always listen, not dispose it, and use a separate socket to handle the server connection, which would probably fix it, but I want other programs to be able to use the port between successive play sessions.

我记得看到另一个问题苦恼,但没有我的情况下,有没有满意的答案。

I remember seeing another question asking this, but there was no satisfactory answer for my case there.

推荐答案

可能有两个原因端口将保持开放,但我认为你应该能够解决您的问题用一个明确的 LingerOption 上的插座:

There may be a couple of reasons why the port would stay open, but I think you should be able to resolve your issue by using an explicit LingerOption on the socket:

LingerOption lo = new LingerOption(false, 0);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, lo);

这基本上是轮番套接字关闭到流产关机,而不是正常关机。如果你希望它是优雅的,但只是没有等待太长的时间,然后用在构造函数中,并指定超时小,但非零值。

This basically turns the socket shutdown into an abortive shutdown instead of a graceful shutdown. If you want it to be graceful but just not wait as long, then use true in the constructor and specify a small but nonzero value for the timeout.

我只注意到这条线,这几乎是无疑是你的问题的一部分:

I just noticed this line, which is almost undoubtedly part of your problem:

server.connection = server.connection.EndAccept(iar); // I will only have one client, so I don't care for the original listening socket.

您已经在这里写的评论是,好了,错了。你的包装类实在不应该让连接要写入的。但你不能简单地取代了监听套接字与客户套接字 - !他们是两个不同的插槽

The comment you've written here is, well, wrong. Your wrapper class really shouldn't allow connection to be written to at all. But you cannot simply replace the listening socket with the client socket - they're two different sockets!

这是怎么回事就发生在这里的是,(一)监听套接字超出范围,因此从来没有得到明确关闭/处理 - 这将发生在一个随机的时间,可能在一个肮脏的时间。和(b)采取关闭套接字只是客户端套接字,也不会关闭监听套接字,所以这也难怪,你遇到了麻烦又重新绑定监听套接字。

What's going to happen here is that (a) the listening socket goes out of scope and therefore never gets explicitly closed/disposed - this will happen at a random time, possibly at a nasty time. And (b) the socket that you do close is just the client socket, it will not close the listening socket, and so it's no wonder that you're having trouble rebinding another listening socket.

你实际上看到的不是一个套接字超时,它需要垃圾收集认识到监听套接字是死的,自由的时间/定稿。为了解决这个问题,你需要停止覆盖监听套接字;你的包装类的处置方法应处置的的监听套接字,并在客户端的插座应单独跟踪和设置时,你实际上是用做吧。

What you're actually witnessing isn't a socket timeout, it's the time it takes for the garbage collector to realize that the listening socket is dead and free/finalize it. To fix this, you need to stop overwriting the listening socket; the Dispose method of your wrapper class should dispose the original listening socket, and the client socket should be tracked separately and disposed whenever you are actually done with it.

其实,你应该永远不需要重新绑定另一个监听套接字的。监听套接字保持活动状态的全部时间。实际的连接,只需在客户端套接字psented重新$ P $。您应该只需要配置监听套接字,当你终于关闭服务器。

In fact, you should really never need to rebind another listening socket at all. The listening socket stays alive the whole time. The actual connection is represented by just the client socket. You should only need to dispose the listening socket when you finally shut down the server.

这篇关于我怎样才能取消绑定在C#中的插座?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆