2013-11-21 5 views
1

Поражайте меня, это сложный вопрос, и это длинный фрагмент кода, но я тянул свои волосы около двух недель, пытаясь добиться этого. работа, уровень разочарования очень-очень высок. Любая помощь приветствуется!C# Сервер асинхронного сокета не получает ответ от Java-клиента.

У меня есть сотовый Java-сервер &, который использует базу данных на основе XML. Я заменяю сервер на C#, основанный на том, что он говорит с базой данных MySQL. Клиент останется как есть до тех пор, пока он не сможет быть заменен, возможно, в начале следующего года, поэтому рассмотрите его полупрозрачную коробку (в лучшем случае) и непреложную.

Мне нужно поддерживать примерно до дюжины или около того клиентов Java за один раз с новым сервером, возможно, несколько десятков, если мы расширим наше оборудование.

Потребовалось достаточно времени, чтобы клиент мог ответить на сервер, но жесткий сервер связывается с клиентом, хотя и очень грубо. Это было мое доказательство концепции, и я подумал, что было бы довольно просто преобразовать код в асинхронный сервер, используя MSDN example &, который я бы отправил. Это было около двух недель назад. В прошлую пятницу мы провели обзор кода, чтобы помочь мне получить жесткий код на асинхронном сервере. Я достиг некоторого успеха, клиент отвечает на его первоначальный контакт с именем пользователя, как и предполагалось, но дальнейшая связь прекращается там (предполагается, что он отправит запрос на основе XML, а сервер ответит на ответ на основе XML).

Предлагаемые программы:

Стартовый сервер;

Стартовый клиент;

посыла Сервер: "Login:", но это может быть в буквальном смысле ничего

Клиент посылает: "USERNAME"

Сервер отправить: "ACCEPTED"

сервер посылает: "ACCEPTED" (понятия не имею почему это так необходимо, но клиент не отвечает на первую отправку сервера, и я не могу его изменить.).

Клиент посыла: <PCBDataBaseCMD><Search><PCBID>33844</PCBID></Search></PCBDataBaseCMD>

Сервер отправить:

<Executing/> 
<PCBDatabaseReply> 
    <SearchResult> 
     <SBE_PCB_Data PCBID='33844'> 
      <Creation ActionID='e2a7' User='DELLIOTTG:192.168.1.214' Date='2013-01-23T13:16:51' PCBID='33844'> 
       <PCBDrawing>10376A</PCBDrawing> 
       <AssemblyDrawing>41528F</AssemblyDrawing> 
       <Vendor>PCA</Vendor> 
       <PONumber>99999</PONumber> 
      </Creation> 
      <Assignment ActionID='e2c1' User='DELLIOTTG:192.168.1.228' Date='2013-01-23T15:30:00' PCBID='33844'> 
       <SBESerialNumber>04104743</SBESerialNumber> 
      </Assignment> 
     </SBE_PCB_Data> 
    </SearchResult> 
</PCBDatabaseReply> 

Этот XML будет отображаться в клиенте, как и ожидалось.

Сбросить & ждать следующего запроса клиента.

Вот жестко закодирован сервер (это будет компилировать как есть):

using System; 
using System.IO; 
using System.Net; 
using System.Net.Sockets; 
using System.Text; 

class MyTcpListener 
{ 
    public static void Main() 
    { 
     Int32 port = 8955; 
     IPAddress localAddr = IPAddress.Parse("192.168.1.137"); 
     TcpListener server = null; 
     server = new TcpListener(localAddr, port); 
     server.Start(); 
     Socket socketForClient = server.AcceptSocket(); 
     NetworkStream stream = new NetworkStream(socketForClient); 
     System.IO.StreamWriter streamWriter = new System.IO.StreamWriter(stream); 
     System.IO.StreamReader streamReader = new System.IO.StreamReader(stream); 
     string response1 = @"<Executing/> 
      <PCBDatabaseReply> 
       <SearchResult> 
        <SBE_PCB_Data PCBID='33844'> 
         <Creation ActionID='e2a7' User='DELLIOTTG:192.168.1.214' Date='2013-01-23T13:16:51' PCBID='33844'> 
          <PCBDrawing>10376A</PCBDrawing> 
          <AssemblyDrawing>41528F</AssemblyDrawing> 
          <Vendor>PCA</Vendor> 
          <PONumber>99999</PONumber> 
         </Creation> 
         <Assignment ActionID='e2c1' User='DELLIOTTG:192.168.1.228' Date='2013-01-23T15:30:00' PCBID='33844'> 
          <SBESerialNumber>04104743</SBESerialNumber> 
         </Assignment> 
        </SBE_PCB_Data> 
       </SearchResult> 
      </PCBDatabaseReply>"; 
     try 
     { 
      while(true) 
      { 
       Console.WriteLine("Waiting for Client connection... "); 
       streamWriter.WriteLine("poke"); //this can literally be anything, just something to let the client know the server's there 
       streamWriter.Flush(); 
       string userName = streamReader.ReadLine(); 
       Console.WriteLine(userName); 
       streamWriter.WriteLine("ACCEPTED"); 
       streamWriter.Flush(); 
       streamWriter.WriteLine("ACCEPTED"); 
       streamWriter.Flush(); 
       string buffer = string.Empty; 
       bool sendFlag = true; 
       ASCIIEncoding encoder = new ASCIIEncoding(); 
       char[] c = new char[512]; 
       while (sendFlag) 
       {    
        streamReader.Read(c, 0, c.Length); 
        buffer += string.Join("", c); 
        streamReader.Read(c, 0, c.Length); 
        buffer += string.Join("", c); 
        Console.WriteLine(buffer); 
        if(streamReader.Peek() < 0) 
        { 
         sendFlag = false; 
        } 
        else 
        { 
         Console.WriteLine("Apparently not at the end?"); 
        } 
       }      
       Console.WriteLine("RECEIVED: " + buffer); 
       //} 
       Console.WriteLine("SEND: " + response1); 
       streamWriter.Write(response1); 
       streamWriter.Flush(); 
      } 
     } 
     catch(ObjectDisposedException ex) 
     { 
      Console.WriteLine("ObjectDisposedException: {0}", ex); 
     } 
     catch(SocketException e) 
     { 
      Console.WriteLine("SocketException: {0}", e); 
     } 
     finally 
     { 
      server.Stop(); 
      streamReader.Dispose(); 
      streamReader.Close(); 
     } 
     Console.WriteLine("\nHit enter to continue..."); 
     Console.Read(); 
    } 
} 

Я передал код на сервер асинхронного, но я должен признать, менее совершенное, чем понимание того, как все части работают вместе и как объект состояния работает для прямого трафика. I думаю связь может быть разрушена в модуле SendCallBack(), потому что я не отправляю сообщение «прекратить прием» или, возможно, сообщение «продолжить с передачей», я не уверен.

Здесь находится асинхронный сервер (этот не будет компилировать, ему не хватает большого количества MySql, обработки командной строки и т. Д. Кода в интересах сокращения его).

public static IPAddress IpAddress { get; set; } 
    private static readonly ManualResetEvent AllDone = new ManualResetEvent(false); 

    public static IPEndPoint GetIpEndPoint() 
    { 
     IpAddress = Dns.GetHostEntry(Dns.GetHostName()).AddressList.FirstOrDefault(addr => addr.AddressFamily.ToString() == "InterNetwork"); 
     if (IpAddress != null) 
     { 
      IPEndPoint localEndPoint = new IPEndPoint(IpAddress, CommandLineOptions.Port); 
      return localEndPoint; 
     } 
     return null; 
    } 
    public class StateObject 
    { 
     public Socket workSocket = null; 
     public const int bufferSize = 1024; 
     public byte[] buffer = new byte[bufferSize]; 
     public string UserName { get; set; } 
     public string XmlContent { get; set; } 
     public StringBuilder sb = new StringBuilder(); 
     public StreamReader sr; 
     public StreamWriter sw; 
    } 
    public static void StartListening(IPEndPoint localEndPoint) 
    { 
     byte[] bytes = new Byte[1024]; 
     Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
     try 
     { 
      listener.Bind(localEndPoint); 
      listener.Listen(100); 
      while (true) 
      { 
       AllDone.Reset(); 
       Console.WriteLine("PCBDatabaseServer online awaiting a connection..."); 
       listener.BeginAccept(AcceptCallback, listener); 
       AllDone.WaitOne(); 
      } 
     } 
     catch (Exception e) 
     { 
      Log.Error(e.ToString()); 
     } 
     Console.WriteLine("\nPress ENTER to continue..."); 
     Console.Read(); 
    } 
    public static void AcceptCallback(IAsyncResult ar) 
    { 
     try 
     { 
      AllDone.Set(); 
      Socket listener = (Socket) ar.AsyncState; 
      Socket handler = listener.EndAccept(ar); 
      NetworkStream nwsHandle = new NetworkStream(handler); 
      StateObject acbState = new StateObject 
       { 
        workSocket = handler, 
        sw = new StreamWriter(nwsHandle) {AutoFlush = true}, 
        sr = new StreamReader(nwsHandle) 
       }; 
      acbState.sw.WriteLine("poke"); 
      handler.BeginReceive(acbState.buffer, 0, StateObject.bufferSize, 0, ReadCallback, acbState); 
      acbState.UserName = Encoding.UTF8.GetString(acbState.buffer); 
      Console.WriteLine(acbState.UserName); 
     } 
     catch (IOException ex) 
     { 
      Console.WriteLine(ex); 
     } 
    } 
    public static void ReadCallback(IAsyncResult ar) 
    { 
     try 
     { 
      StateObject rcbState = (StateObject) ar.AsyncState; 
      rcbState.sw.Write("ACCEPTED");//**this double call is required, the client has two ReadLine() statements, pretty sure the first write could be anything, and it only sees the second one, but I can't change the client** 
      rcbState.sw.Write("ACCEPTED"); 
      string testMeToo = string.Empty;//this is where I'm trying to capture the XML data from the client, which should end up in rcbState.XmlContent, but I'm flailing here trying to get this to work. 
      bool sendFlag = true; 
      char[] c = new char[512]; 
      while (sendFlag) 
      { 
       rcbState.sr.Read(c, 0, c.Length); 
       testMeToo = string.Join("", c); 
       rcbState.sr.Read(c, 0, c.Length); 
       testMeToo += string.Join("", c); 
       Console.WriteLine(testMeToo); 
       if (rcbState.sr.Peek() < 0) 
       { 
        sendFlag = false; 
       } 
       else 
       { 
        Console.WriteLine("Apparently not at the end?"); 
       } 
      } 
      Console.WriteLine("RECEIVED: " + testMeToo); 
      rcbState.workSocket.BeginReceive(rcbState.buffer, 0, StateObject.bufferSize, 0, AcceptCallback, rcbState); 
      rcbState.XmlContent = Encoding.UTF8.GetString(rcbState.buffer); 
      Console.WriteLine("XML: " + rcbState.XmlContent); 
      rcbState.XmlContent += Encoding.UTF8.GetString(rcbState.buffer); 
      Console.WriteLine("XML: " + rcbState.XmlContent); 
      int bytesRead = rcbState.workSocket.EndReceive(ar); 
      string content = string.Empty; 
      //**things break down here, you can ignore this if statement** 
      if (bytesRead > 0) 
      { 
       while (bytesRead > 0) 
       { 
        rcbState.sb.Append(Encoding.ASCII.GetString(rcbState.buffer, 0, bytesRead)); 
        content = rcbState.sb.ToString(); 
       } 
       if (true) 
       { 
        Console.WriteLine("Read {0} bytes from socket. \nData : {1}", content.Length, content); 
        Console.WriteLine(content); 
        Send(rcbState.workSocket, content); 
       } 
       else 
       { 
        rcbState.workSocket.BeginReceive(rcbState.buffer, 0, StateObject.bufferSize, 0, ReadCallback, rcbState); 
       } 
      } 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine(ex); 
     } 
    } 
    private static void Send(Socket handler, String data) 
    { 
     byte[] byteData = Encoding.ASCII.GetBytes(data); 
     NetworkStream nwsHandle = new NetworkStream(handler); 
     StateObject sendState = new StateObject 
      { 
       workSocket = handler, 
       sw = new StreamWriter(nwsHandle) {AutoFlush = true} 
      }; 
     sendState.sw.Write(data); 
    } 
    //here is where I think the communication is breaking down, I think the client may be waiting for some signal to tell it to send the next bit, but I can't figure out what that may be. 
    private static void SendCallback(IAsyncResult ar) 
    { 
     try 
     { 
      Socket listener = (Socket)ar.AsyncState; 
      Socket handler = listener.EndAccept(ar); 
      NetworkStream nwsListen = new NetworkStream(listener); 
      NetworkStream nwsHandle = new NetworkStream(handler); 
      StateObject scbState = new StateObject 
      { 
       workSocket = handler, 
       sw = new StreamWriter(nwsHandle) { AutoFlush = true }, 
       sr = new StreamReader(nwsListen) 
      }; 
      int bytesSent = scbState.workSocket.EndSend(ar); 
      Console.WriteLine("Sent {0} bytes to client.", bytesSent); 
      handler.Shutdown(SocketShutdown.Both); 
      handler.Close(); 
     } 
     catch (Exception e) 
     { 
      Log.Error(e.ToString()); 
     } 
    } 
    #endregion 
} 

}

Вот некоторые ссылки я исследовал, первый родственный вопрос, который я написал некоторое время назад:
Source-less black box client

C#<> Java socket communications

How to write a scalable TCP/IP based server

C# High Performance Socket Code

ответ

0

Пара вещей, чтобы рассмотреть следующие вопросы:

  1. Вашего AllDone.Wait() будет блокировать ваши принимать нити во время вести разговор с клиентом. Этот тип побеждает цель асинхронного ввода-вывода, так как вы хотите, чтобы сервер возвращался к прослушиванию подключений, как только он принимает соединение, иначе ваша обработка будет сериализована.

  2. BeginReceive (...) немедленно возвращается и вы присваиваете данные из буфера чтения переменной, когда чтение может быть неполным.

  3. В своем обратном вызове вы получаете более асинхронные сообщения (BeginReceive). Не уверен, что это то, что вы намереваетесь с тех пор, как вы уже работаете в потоке, отдельно от основного потока вашего сервера. Вы можете захотеть использовать rcbState.workSocket.Receive (...) вместо BeginReceive(), который, кстати, вернется к вашему обратному вызову accept, который должен быть для приема соединений, не завершающих чтение. Таким образом, кажется, что логика ошибочна.

Так мое общее предложение заключается в том, как только вы получите в вашу Accept использования обратного вызова синхронно считывает и записывает на новом сокете вы получаете, как это кажется, от того, что я могу сказать, у вас есть ряд клиент/серверные взаимодействия для завершения «транзакции». Кажется, нет никакой пользы при выполнении дополнительных асинхронных операций чтения/записи, как только вы принимаете соединение с клиентом. Вы просто сбиваете с толку, делая асинхронные чтения/записи в это время.

+0

Спасибо за совет, я буду первым, кто признается, что я в замешательстве! Сегодня я буду судить об этом и посмотреть, могу ли я использовать ваши комментарии. Я думаю, вы, возможно, столкнулись с проблемой транзакции, связанной с чтением и записью async & sync. Надеюсь, я очень надеюсь на это. – delliottg

Смежные вопросы