C # TCP Socket.Receive проблема при повторном использовании сокета - PullRequest
2 голосов
/ 06 января 2012

предисловие:

Я уже давно нахожусь в тупике, и мне не очень повезло найти то, что мне нужно. У меня есть служба C # (.NET 3.5). Один поток действует как асинхронный прослушиватель для входящих соединений TCP. Когда данные поступают, я порождаю новый рабочий поток для обработки данных и отправляю подтверждение обратно.

Во втором потоке того же сервиса мы отправляем команды, до сегодняшнего дня он собирал информацию из базы данных, строил новый сокет, подключался, затем отправлял команду, и я использую Socket.Receive для вызова блокировки и дождитесь ответа (или пока не истечет время ожидания).

Все работало отлично, пока новому клиенту не нужно было отправлять нам данные так быстро (с интервалами в 5-10 секунд), что мы больше не можем открывать новый сокет, чтобы выполнить команду. Поэтому я начал изучать, когда нужно отправить команду, чтобы к потоку «слушателя» был подключен клиент. Если этот клиент подключен, используйте этот сокет вместо создания нового.

Проблема: Я дошел до того, что могу отправить свою команду обратно в тот же сокет, который получает слушатель, но когда клиент отправляет данные обратно в качестве ответа, он дважды использует метод Socket.Receive для фактического запуска, думая, что он получил данные. Первый раз он попадает в мой класс слушателя, второй раз - в мой командный класс, где я действительно хочу, чтобы он был.

Вопрос: Есть ли какая-либо опция или что-то, что мне нужно сделать перед вызовом моего метода Socket.Receive, чтобы убедиться, что данные попадают в правильное место?

В моем классе слушателя у меня есть список объектов "CSocketPacket"

public class CSocketPacket
{
   public CSocketPacket(System.Net.Sockets.Socket socket)
   {
      thisSocket = socket;
      this.IpAddress =
          ((System.Net.IPEndPoint)socket.RemoteEndPoint).Address.ToString();
   }

   public System.Net.Sockets.Socket thisSocket;
   public byte[] dataBuffer = new byte[BUFFER_SIZE];
   public string IpAddress; //Use this to search for the socket
}

Затем, когда я посылаю команду, я создаю новый объект сокета tcp:

client = new Socket(
   AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ep = new IPEndPoint(
   IPAddress.Parse(Strings.Trim(ipAddress)), port);
IPEndPoint LocalIp = new IPEndPoint(IPAddress.Parse(
   System.Configuration.ConfigurationManager.AppSettings["SourceIP"]), port);

затем я просматриваю список своих слушателей, чтобы узнать, подключен ли этот сокет:

if (listener.SocketExists(ipAddress)) 
{
   // set the client socket in this class to the 
   // instance of the socket from the listener class
   SocketIndex = listener.FindSocketInList(ipAddress);
   if (SocketIndex != -1)
   {
      // might need to figure out how to avoid copying the socket
      // to a new variable ???
      client = listener.ConnectedSockets[SocketIndex].thisSocket;
      SocketBeingReUsed = true;
   }
}
else
{
   // try to connect to the client
   client.Connect(ep);
}

наконец я прошёл все этапы отправки и получения

if (client.Connected)
{
   if (client.Poll(1000, SelectMode.SelectWrite))
   {
      int sentAmount = Send(ref client);
      client.ReceiveTimeout = 90000; //90 seconds
      returnData = ReceiveData(ref client, sentAmount);
   }
}

все работает до точки в моем методе ReceiveData (ref client, sentAmount), где я вызываю метод Socket.Receive(data, total, Socket.ReceiveBufferSize, SocketFlags.None);.

Я использовал инструмент под названием Hercules для проверки отправки / получения пакетов на двух машинах в моей домашней сети.

У кого-нибудь есть идеи, что я могу сделать, чтобы решить эту проблему? Я прошу прощения за такой длинный вопрос, но я хочу попытаться дать как можно больше информации, а не вставлять весь мой проект. Я за любые предложения.

Отказ от ответственности: я написал этот код около 3 лет назад, так что я стараюсь делать то, чего не должен быть, я уверен : P

Спасибо всем, кто это прочитал.

С уважением,

Chris

1 Ответ

1 голос
/ 07 января 2012

ОК, теперь я следую за вами! Учитывая то, что вы сказали в комментариях выше, способ решения проблемы состоит в том, чтобы иметь один класс / поток, который читает из сокета (который в любом случае является правильным способом чтения из сокетов), а затем он будет координировать, какой класс получает данные. Я думаю, что это может работать немного как шаблон проектирования команд .

...