2015-02-15 2 views
0

Я пробую базовый проект по подключению к разъему. Я создал следующий вид:Подключение к разъему отправляет одно сообщение, но не более

enter image description here

Задача довольно проста. Я собираюсь отправить сообщение слева, а затем получить справа.

Мой код выглядит следующим образом:

private bool _senderStarted = false; 
private bool _listenerStarted = false; 

private Socket sListener; 
private ManualResetEvent listenerNotifier = new ManualResetEvent(false); 

private Socket sSender; 
private IPEndPoint senderEndpoint = null; 

public Form1() 
{ 
    InitializeComponent(); 
} 
private void Form1_Load(object sender, EventArgs e) 
{ 
    // Create sockets 
    sListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
    sSender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
} 
private void btnSenderStart_Click(object sender, EventArgs e) 
{ 
    _senderStarted = true; 
    btnSenderStart.Enabled = false; 
    btnSenderStop.Enabled = true; 
    txtMessage.Enabled = true; 
    btnSend.Enabled = true; 
    txtMessage.Clear(); 
    txtMessage.Focus(); 
    lstSender.Items.Clear(); 
    // Create sender endpoint 
    string[] arr = txtSenderIP.Text.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries); 
    byte[] ips = arr.Select(x => byte.Parse(x)).ToArray(); 
    IPAddress senderAddress = new IPAddress(ips); 
    senderEndpoint = new IPEndPoint(senderAddress, (int)txtSenderPort.Value); 
    sSender.Connect(senderEndpoint); 
} 
private void btnListenerStart_Click(object sender, EventArgs e) 
{ 
    _listenerStarted = true; 
    btnListenerStart.Enabled = false; 
    btnListenerStop.Enabled = true; 
    lstListener.Items.Clear(); 
    // Create listener endpoint 
    string[] arr = txtListenerIP.Text.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries); 
    byte[] ips = arr.Select(x => byte.Parse(x)).ToArray(); 
    IPAddress listenerAddress = new IPAddress(ips); 
    IPEndPoint listenerEndpoint = new IPEndPoint(listenerAddress, (int)txtSenderPort.Value); 
    // Bind listener to endpoint 
    sListener.Bind(listenerEndpoint); 
    bwListener.RunWorkerAsync(); 
} 
private void btnSenderStop_Click(object sender, EventArgs e) 
{ 
    _senderStarted = false; 
    btnSenderStart.Enabled = true; 
    btnSenderStop.Enabled = false; 
    txtMessage.Enabled = false; 
    btnSend.Enabled = false; 
    txtMessage.Clear(); 
} 
private void btnListenerStop_Click(object sender, EventArgs e) 
{ 
    _listenerStarted = false; 
    btnListenerStart.Enabled = true; 
    btnListenerStop.Enabled = false; 
} 
#region Listener 
private void AcceptCallback(IAsyncResult ar) 
{ 
    // Signal the main thread to continue. 
    listenerNotifier.Set(); 
    // Get the socket that handles the client request. 
    Socket listener = (Socket)ar.AsyncState; 
    Socket handler = listener.EndAccept(ar); 
    // Create the state object. 
    StateObject listenerState = new StateObject(); 
    listenerState.workSocket = handler; 
    handler.BeginReceive(listenerState.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), listenerState); 
} 
public void ReadCallback(IAsyncResult ar) 
{ 
    String content = String.Empty; 
    // Retrieve the state object and the handler socket from the asynchronous state object. 
    StateObject state = (StateObject)ar.AsyncState; 
    Socket handler = state.workSocket; 

    // Read data from the client socket. 
    int bytesRead = handler.EndReceive(ar); 

    if (bytesRead > 0) 
    { 
     // There might be more data, so store the data received so far. 
     state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead)); 
     // Check for end-of-file tag. If it is not there, read more data. 
     content = state.sb.ToString(); 

     this.Invoke(new MethodInvoker(delegate() 
     { 
      lstListener.Items.Add(content); 
     })); 
    } 
} 
#endregion 

private void btnSend_Click(object sender, EventArgs e) 
{ 
    byte[] byteData = Encoding.ASCII.GetBytes(txtMessage.Text); 
    sSender.Send(byteData); 
    txtMessage.Clear(); 
    txtMessage.Focus(); 
} 

private void bwListener_DoWork(object sender, DoWorkEventArgs e) 
{ 
    sListener.Listen(10); 
    while (_listenerStarted) 
    { 
     // Set the event to nonsignaled state. 
     listenerNotifier.Reset(); 
     // Start an asynchronous socket to listen for connections. 
     sListener.BeginAccept(new AsyncCallback(AcceptCallback), sListener); 
     // Wait until a connection is made before continuing. 
     listenerNotifier.WaitOne(); 
    } 
} 

Я могу послать mesasage успешно, как показано на рисунке. но когда я пытаюсь отправить второе сообщение, похоже, что он отправляет сообщение, слушатель вообще не получает никакого сообщения. Что мне не хватает, или что я должен исправить?

С уважением.

ответ

1

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

Например:

public void ReadCallback(IAsyncResult ar) 
{ 
    String content = String.Empty; 
    // Retrieve the state object and the handler socket from the asynchronous state object. 
    StateObject state = (StateObject)ar.AsyncState; 
    Socket handler = state.workSocket; 

    // Read data from the client socket. 
    int bytesRead = handler.EndReceive(ar); 

    if (bytesRead > 0) 
    { 
     // There might be more data, so store the data received so far. 
     state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead)); 
     // Check for end-of-file tag. If it is not there, read more data. 
     content = state.sb.ToString(); 

     this.Invoke(new MethodInvoker(delegate() 
     { 
      lstListener.Items.Add(content); 
     })); 

     handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state); 
    } 
} 

(Как в сторону: я видел целый ряд вопросов, в последнее время, которые следуют за подобный стиль кода, который вы используете – соглашения об именах, дизайн класса, логический поток, и т. д. –, который заставляет меня поверить, что все они получены из общего примера кода где-то. К сожалению, это не очень хорошая реализация сетевого ввода-вывода. Мне жаль, что я не знал, откуда эти примеры пришли из hellip, было бы неплохо увидеть пример исходного кода в контексте).

+0

Большое спасибо за ваш ответ. К сожалению, я не смогу попробовать ваш код, пока я не вернусь домой после работы, но я буду и я ценю ваши усилия. – user3021830

+0

О стиле кодирования и соглашениях, у меня есть несколько вопросов и ответов на сайте, которые вы могли бы поразить раньше. Но если вы spesifically указываете код ввода-вывода, я привел примеры из примеров MSDN (https://msdn.microsoft.com/en-us/library/fx6588te(v=vs.110).aspx, https: // msdn.microsoft.com/en-us/library/bew39x2a(v=vs.110).aspx) и использовал фонового работника просто для простоты, потому что, когда я начал слушать, я не мог начать отправку в той же форме, потому что Thread Пользовательский интерфейс работает в одном потоке. – user3021830

+0

И только для того, чтобы сообщить, какая распространенная ошибка вы ощущаете в стиле кодирования и каково ваше мнение, чтобы сделать ее лучше? С уважением. – user3021830

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