У меня есть интерфейс сокета клиент / сервер .NET 3.5, использующий асинхронные методы. Клиент подключается к серверу, и соединение должно оставаться открытым, пока приложение не завершится. Протокол состоит из следующего шаблона:
- отправить STX
- получить подтверждение
- отправка данных1
- получить подтверждение
- отправить данные2 (повторите 5-6, пока больше данных)
- получить подтверждение
- отправить etx
Таким образом, одна транзакция с двумя блоками данных, как указано выше, будет состоять из 4 отправлений от клиента. После отправки etx клиент просто ожидает отправки дополнительных данных, а затем начинает следующую передачу с помощью stx. Я не хочу разрывать соединение между отдельными биржами или после каждой полезной нагрузки stx / data / etx.
Прямо сейчас, после подключения, клиент может отправить первый stx и получить один ack, но после этого я не могу поместить больше данных в провод. Ни одна из сторон не отсоединяется, розетка все еще не повреждена. Код клиента серьезно сокращен следующим образом - я следую шаблону, обычно доступному в онлайн-примерах кода.
private void SendReceive(string data) {
// ...
SocketAsyncEventArgs completeArgs;
completeArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnSend);
clientSocket.SendAsync(completeArgs);
// two AutoResetEvents, one for send, one for receive
if ( !AutoResetEvent.WaitAll(autoSendReceiveEvents , -1) )
Log("failed");
else
Log("success");
// ...
}
private void OnSend( object sender , SocketAsyncEventArgs e ) {
// ...
Socket s = e.UserToken as Socket;
byte[] receiveBuffer = new byte[ 4096 ];
e.SetBuffer(receiveBuffer , 0 , receiveBuffer.Length);
e.Completed += new EventHandler<SocketAsyncEventArgs>(OnReceive);
s.ReceiveAsync(e);
// ...
}
private void OnReceive( object sender , SocketAsyncEventArgs e ) {}
// ...
if ( e.BytesTransferred > 0 ) {
Int32 bytesTransferred = e.BytesTransferred;
String received = Encoding.ASCII.GetString(e.Buffer , e.Offset , bytesTransferred);
dataReceived += received;
}
autoSendReceiveEvents[ SendOperation ].Set(); // could be moved elsewhere
autoSendReceiveEvents[ ReceiveOperation ].Set(); // releases mutexes
}
Код на сервере очень похож, за исключением того, что он сначала получает, а затем отправляет ответ - сервер ничего не делает (что я могу сказать), чтобы изменить соединение после отправки ответа. Проблема в том, что во второй раз, когда я нажимаю SendReceive на клиенте, соединение уже находится в странном состоянии.
Нужно ли что-то делать в клиенте, чтобы сохранить SocketAsyncEventArgs и повторно использовать один и тот же объект в течение всего времени жизни сокета / соединения? Я не уверен, какой объект eventargs должен зависать в течение жизни соединения или данного обмена.
Нужно ли что-то делать или не делать что-то на сервере, чтобы он продолжал получать данные?
Настройка сервера и обработка ответов выглядит следующим образом:
void Start() {
// ...
listenSocket.Bind(...);
listenSocket.Listen(0);
StartAccept(null); // note accept as soon as we start. OK?
mutex.WaitOne();
}
void StartAccept(SocketAsyncEventArgs acceptEventArg) {
if ( acceptEventArg == null )
{
acceptEventArg = new SocketAsyncEventArgs();
acceptEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(OnAcceptCompleted);
}
Boolean willRaiseEvent = this.listenSocket.AcceptAsync(acceptEventArg);
if ( !willRaiseEvent )
ProcessAccept(acceptEventArg);
// ...
}
private void OnAcceptCompleted( object sender , SocketAsyncEventArgs e ) {
ProcessAccept(e);
}
private void ProcessAccept( SocketAsyncEventArgs e ) {
// ...
SocketAsyncEventArgs readEventArgs = new SocketAsyncEventArgs();
readEventArgs.SetBuffer(dataBuffer , 0 , Int16.MaxValue);
readEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnIOCompleted);
readEventArgs.UserToken = e.AcceptSocket;
dataReceived = ""; // note server is degraded for single client/thread use
// As soon as the client is connected, post a receive to the connection.
Boolean willRaiseEvent = e.AcceptSocket.ReceiveAsync(readEventArgs);
if ( !willRaiseEvent )
this.ProcessReceive(readEventArgs);
// Accept the next connection request.
this.StartAccept(e);
}
private void OnIOCompleted( object sender , SocketAsyncEventArgs e ) {
// switch ( e.LastOperation )
case SocketAsyncOperation.Receive:
ProcessReceive(e); // similar to client code
// operate on dataReceived here
case SocketAsyncOperation.Send:
ProcessSend(e); // similar to client code
}
// execute this when a data has been processed into a response (ack, etc)
private SendResponseToClient(string response) {
// create buffer with response
// currentEventArgs has class scope and is re-used
currentEventArgs.SetBuffer(sendBuffer , 0 , sendBuffer.Length);
Boolean willRaiseEvent = currentClient.SendAsync(currentEventArgs);
if ( !willRaiseEvent )
ProcessSend(currentEventArgs);
}
При отправке ABC трассировка .NET показывает следующее:
Socket#7588182::SendAsync()
Socket#7588182::SendAsync(True#1)
Data from Socket#7588182::FinishOperation(SendAsync)
00000000 : 41 42 43 0D 0A
Socket#7588182::ReceiveAsync()
Exiting Socket#7588182::ReceiveAsync() -> True#1
И это останавливается там. Это выглядит так же, как первая отправка от клиента, но сервер не показывает активности.
Я думаю, что это может быть перегрузка информацией, но я буду рад предоставить более подробную информацию по мере необходимости.
Спасибо!