У меня проблемы с повторным использованием сокета сервера в тестовом приложении, которое я создал. По сути, у меня есть программа, которая реализует как на стороне клиента, так и на стороне сервера. Я запускаю два экземпляра этой программы для целей тестирования: один экземпляр начинает хост, а другой подключается. Это код прослушивания:
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()
для объекта server
, реализованного так:
public void Dispose()
{
connection.Close(); // connection is the actual socket
commandBuff.Clear(); // this is just a StringBuilder
}
У меня также есть это в конструкторе объектов:
public ConnectionWrapper()
{
commandBuff = new StringBuilder();
connection = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
connection.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
}
Я не получаю ошибку, когда нажимаю кнопку Listen
во второй раз. Клиентская сторона подключается просто отлично, однако моя серверная сторона не обнаруживает клиентское соединение второй раз, что в любом случае делает сервер бесполезным. Я предполагаю, что он подключается к старому, давнишнему разъему, но я понятия не имею, почему это происходит, если честно. Вот код подключения клиента:
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()
. Я прочитал, что это нормально, и есть тайм-аут для того порта, чтобы быть "свободным".
Есть ли способ, которым я могу принудительно отключить этот порт или установить очень короткий таймаут, пока он автоматически не освободится? Прямо сейчас, он освобождается только при выходе из программы. Может я что-то не так делаю на своем сервере? Если так, что это могло быть? Почему клиент подключается нормально, но серверная сторона не обнаруживает его во второй раз?
Я мог бы заставить сокет всегда слушать, не распоряжаться им и использовать отдельный сокет для обработки соединения с сервером, что, вероятно, исправит это, но я хочу, чтобы другие программы могли использовать порт между последовательными сеансами воспроизведения.
Я помню, как видел другой вопрос, задающий этот вопрос, но там не было удовлетворительного ответа для моего случая.