【问题标题】:My Server/Listener lacks True Grit我的服务器/听众缺乏真正的勇气
【发布时间】:2012-02-04 09:54:27
【问题描述】:

我的服务器/听众有 ADD 或没有耐力;什么是解毒剂?

应用程序充当套接字通信的两端。第一条消息似乎工作正常(我在 textBox1 中输入“Bla”,然后 label1 读取“Bla back atcha”,但在后续消息中失败。我有一个应用程序实例在我的开发机器上运行,另一个实例(重命名为包含单词“Server”)在另一台机器上。

我粘贴了下面的代码,第二次尝试发送消息时收到的错误消息(“无法建立连接,因为目标机器主动拒绝了它 10.24.93.110:51111”)。

当我在另一台机器上启动“服务器”实例并在命令行中运行“netstat -a”时,它表示服务器机器正在侦听我的开发机器的端口 51111。

在第一条消息传递之后,显然收到并返回,运行“netstat -a”仍然显示与我的开发机器的连接,但该状态不再是 LISTENING 而是 TIME_WAIT。

然后,我尝试传递另一条消息,我得到了错误消息(下面的图表 B)

展览 A:来源

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Diagnostics;

namespace testSocketSendAndReceive_Nutshell
{
    public partial class Form1 : Form
    {
        string sJerrysIPAddr = "10.24.31.110";
        string sMyIPAddr = "10.24.31.128";
        string sThisAppFileName = string.Empty;
        bool bThisInstanceFunctionsAsServer = false;

        internal static Form1 MainSocketPairForm = null;

        public Form1()
        {
            InitializeComponent();
            MainSocketPairForm = this;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            sThisAppFileName = System.Diagnostics.Process.GetCurrentProcess().ProcessName;
            lblFileName.Text = sThisAppFileName;

            // Client and Server code are here combined in one app; however, we want each instance to run as
            // just one or the other, so (the .exe functioning as a Server should be renamed with the subString
            // "Server" somewhere in the filename):
            bThisInstanceFunctionsAsServer = sThisAppFileName.Contains("Server");
            if (bThisInstanceFunctionsAsServer)
            {
                new Thread(Server).Start();       // Run server method concurrently.
                Thread.Sleep(500);                // Give server time to start.
            }
            btnSendMsg.Visible = !bThisInstanceFunctionsAsServer;
        }

        static void Client()
        {
            using (TcpClient client = new TcpClient(Form1.MainSocketPairForm.sJerrysIPAddr, 51111)) // err here second time 
            using (NetworkStream n = client.GetStream())
            {
                BinaryWriter w = new BinaryWriter(n);
                w.Write(Form1.MainSocketPairForm.textBox1.Text.ToString());
                w.Flush();
                Form1.MainSocketPairForm.label1.Text = new BinaryReader(n).ReadString();
            }
        }

        static void Server()     // Handles a single client request, then exits.
        {
            TcpListener listener = new TcpListener(IPAddress.Any, 51111);
            listener.Start(); //Only one usage of each socket address (protocol/network address/port) is normally permitted
            // got the above err msg with an instance running and listening on jerry's machine
            // continues to listen even after shut down...
            using (TcpClient c = listener.AcceptTcpClient())
            using (NetworkStream n = c.GetStream())
            {
                string msg = new BinaryReader(n).ReadString();
                BinaryWriter w = new BinaryWriter(n);
                w.Write(msg + " back atcha!");
                w.Flush(); // Must call Flush because we're not disposing the writer.
            }
            listener.Stop();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Client();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            Close();
        }
    }
}

图表 B:完整的错误消息

System.Net.Sockets.SocketException 未处理 Message="无法连接,因为目标机器主动拒绝 10.24.93.110:51111" 来源="系统" 错误代码=10061 本机错误代码=10061 堆栈跟踪: 在 System.Net.Sockets.TcpClient..ctor(字符串主机名,Int32 端口) 在 testSocketSendAndReceive_Nutshell.Form1.Client() 中 C:\testSocketSendAndReceive_Nutshell\testSocketSendAndReceive_Nutshell\Form1.cs:第 57 行 在 C:\testSocketSendAndReceive_Nutshell\testSocketSendAndReceive_Nutshell\Form1.cs 中的 testSocketSendAndReceive_Nutshell.Form1.button1_Click(Object sender, EventArgs e):System.Windows.Forms.Control.OnClick(EventArgs e) 的第 90 行 在 System.Windows.Forms.Button.OnClick(EventArgs e) 在 System.Windows.Forms.Button.OnMouseUp(MouseEventArgs 事件) 在 System.Windows.Forms.Control.WmMouseUp(消息和 m,MouseButtons 按钮,Int32 点击) 在 System.Windows.Forms.Control.WndProc(消息和 m) 在 System.Windows.Forms.ButtonBase.WndProc(消息和 m) 在 System.Windows.Forms.Button.WndProc(消息和 m) 在 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(消息& m) 在 System.Windows.Forms.Control.ControlNativeWindow.WndProc(消息和 m) 在 System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd,Int32 msg,IntPtr wparam,IntPtr lparam) 在 System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(味精和味精) 在 System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID,Int32 原因,Int32 pvLoopData) 在 System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 原因, ApplicationContext 上下文) 在 System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 原因,ApplicationContext 语境) 在 System.Windows.Forms.Application.Run(窗体 mainForm) 在 testSocketSendAndReceive_Nutshell.Program.Main() 中 C:\testSocketSendAndReceive_Nutshell\testSocketSendAndReceive_Nutshell\Program.cs:第 18 行 在 System.AppDomain._nExecuteAssembly(程序集程序集,字符串 [] 参数) 在 System.AppDomain.ExecuteAssembly(字符串 assemblyFile,证据 assemblySecurity,String [] args) 在 Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() 在 System.Threading.ThreadHelper.ThreadStart_Context(对象状态) 在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback 回调, 对象状态) 在 System.Threading.ThreadHelper.ThreadStart() 内部异常:

【问题讨论】:

    标签: c# sockets


    【解决方案1】:

    查看服务器代码开头的注释

    static void Server()     // Handles a single client request, then exits.
    

    完全正确——你调用一次AcceptTcpClient,响应,然后关闭监听器。那只会处理一个连接。如果您希望它处理多个连接,则需要循环 - 很可能在循环并再次接受之前将每个 TCP 客户端移交给单独的线程。

    【讨论】:

      【解决方案2】:

      您对Server() 方法的评论回答了您自己的问题:

      // Handles a single client request, then exits.
      

      读取第一个字符串后,调用listener.Stop(),然后从函数中返回,因此线程退出。如果您希望服务器在后续请求中保持活动状态,则必须合并某种循环。

      【讨论】:

        【解决方案3】:

        在您的服务器上,您将在收到第一条消息后处理客户端。

        如果要保持 TCP 连接处于活动状态,则需要将 TCP 客户端保存在服务器方法中。然后您可以使用client.GetStream().Read() 之类的方法从客户端读取数据。请注意,此方法将阻塞,直到您收到来自流的消息。

        为了处理 n 个请求,你必须做一些循环:

        while(true) {
           string msg = client.GetStream().Read();
           // do something with the message
        }
        

        还有异步方法允许您在另一个线程上执行这些操作。查看流中的BeginRead() 方法。

        【讨论】:

          【解决方案4】:

          您需要在发送响应后调用client.Close()需要围绕服务器的接受逻辑循环:

          var shouldExit == false;
          while (!shouldExit)
              using (TcpClient c = listener.AcceptTcpClient())
              {
                  using (NetworkStream n = c.GetStream())
                  {
                      string msg = new BinaryReader(n).ReadString();
                      if (msg == "exit")
                          // Client told us to exit...
                          shouldExit = true;
                      BinaryWriter w = new BinaryWriter(n);
                      w.Write(msg + " back atcha!");
                      w.Flush(); // Must call Flush because we're not disposing the writer.
                  }
              }
          

          这一切都在文档中的示例中:http://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener.aspx

          【讨论】:

          • 这里不需要调用Close() - 它在using 语句中,所以它会被自动处理。循环是问题所在。
          猜你喜欢
          • 2021-06-03
          • 2018-01-31
          • 1970-01-01
          • 2011-11-02
          • 1970-01-01
          • 2012-02-29
          • 2017-01-18
          • 2021-06-11
          • 2017-03-14
          相关资源
          最近更新 更多