如何在线程中控制(访问)TcpClients流

时间:2014-10-09 19:10:00

标签: c# multithreading sockets

从现在开始,我试图在c#中学习Socketing编程。我一直在寻找许多msdn,stackoverflow和代码项目项目,讨论和示例。

我重写了它们,我使用了调试和"步骤-in"在Visual Studio中,我一行一行地接受了它,现在我正在进行我的小项目。"这是一个迷你聊天(控制台应用程序)。让我来描述代码,在底部我会告诉你我的问题。

服务器

主:

  1. 我已经启动了一个服务器,一个TcpListener在ip 0.0.0.0和端口8000上。

  2. 我已经在接受我的客户端的方法上创建了一个线程(使用了3个线程,这是其中之一,第一个)并启动它。

  3. 方法接受客户:

    1. 我已使用TcpClient接受TcpListenerwhile(true)的Tcp客户端。

    2. 我已从该客户端获取了该流,并且我已在该流上创建了一个streamReader和一个streamWriter。

    3. 我已经创建了第二个帖子,我已经完成了写作的逻辑。

    4. 我已经盯着巫婆的第三个帖子,我已经完成了阅读的逻辑。

    5. 以下是代码:

      using System;
      using System.Collections.Generic;
      using System.IO;
      using System.Linq;
      using System.Net;
      using System.Net.Sockets;
      using System.Text;
      using System.Threading;
      using System.Threading.Tasks;
      
      namespace TcpServer
      {
          class TcpServer
          {
              static TcpListener tcpL;
              static TcpClient tcpC;
              static NetworkStream nStream;
              static StreamWriter sW;
              static StreamReader sR;
              static List<TcpClient> lTcp;
      
              static void Main(string[] args)
              {
                  Console.WriteLine(" >> Server Started");
                  tcpL = new TcpListener(IPAddress.Parse("0.0.0.0"), 8000);
                  tcpL.Start();
                  Thread accClients = new Thread(acceptClients);
                  int counter = 0;
                  accClients.Start(counter);
      
      
                  Console.ReadLine();
              }
      
              private static void acceptClients(object obj)
              {
      
                  while (true)
                  {
                      tcpC = tcpL.AcceptTcpClient();
      
                      Console.WriteLine(" >> Client Connected");
                      nStream = tcpC.GetStream();
                      sW = new StreamWriter(nStream);
                      sR = new StreamReader(nStream);
                      Console.WriteLine(" >> Data Transfer Established");
      
      
                      Thread thWrite = new Thread(doWriteing);
                      thWrite.Start(sW);
                      Thread thRead = new Thread(doReading);
                      thRead.Start(sR);
      
                  }
              }
      
              private static void doWriteing(object obj)
              {
                  StreamWriter sW = (StreamWriter)obj;
                  while (true)
                  {
                      sW.WriteLine(Console.ReadLine());
                      sW.Flush();
                  }
              }
      
              private static void doReading(object obj)
              {
                  StreamReader sR = (StreamReader)obj;
      
                  while (true)
                  {
                      string linie;
                      try
                      {
                          linie = sR.ReadLine();
                          Console.WriteLine(linie);
      
                      }
                      catch (Exception)
                      {
                          continue;
                      }
                  }
              }
          }
      }
      

      和客户:

      这个很简单。

      主:

      1. 我在ip 127.0.0.1和端口8000上连接了TcpClient

      2. 我已经从TcpClient获得了流。

      3. 在该流上创建了StreamWriterStreamReader

      4. 开始写作和阅读2个主题。

      5. 以下是代码:

        using System;
        using System.Collections.Generic;
        using System.IO;
        using System.Linq;
        using System.Net.Sockets;
        using System.Text;
        using System.Threading;
        using System.Threading.Tasks;
        
        namespace TCPClient
        {
            class TCPClient
            {
                static TcpClient tcpC;
                static NetworkStream nStream;
                static void Main(string[] args)
                {
                    Console.WriteLine(" >> Client Started");
                    tcpC = new TcpClient("127.0.0.1", 8000);
                    Console.WriteLine(" >> Client Connected");
        
                    nStream = tcpC.GetStream();
                    StreamWriter sW = new StreamWriter(nStream);
                    StreamReader sR = new StreamReader(nStream);
        
                    Thread thWrite = new Thread(doWriteing);
                    thWrite.Start(sW);
                    Thread thRead = new Thread(doReading);
                    thRead.Start(sR);
        
                    Console.ReadLine();
                }
        
                private static void doWriteing(object obj)
                {
                    StreamWriter sW = (StreamWriter)obj;
                    while (true)
                    {
                        sW.WriteLine(Console.ReadLine());
                        sW.Flush();
                    }
                }
        
                private static void doReading(object obj)
                {
                    StreamReader sR = (StreamReader)obj;
                    while (true)
                    {
                        string linie;
                        try
                        {
                            linie = sR.ReadLine();
                            Console.WriteLine(linie);
                        }
                        catch (Exception)
                        {
                            continue;
                        }
                    }
                }
            }
        }
        

        现在我有三大问题:

        1. 为什么,或者可能&#34;如何&#34;,服务器按照创建的顺序将数据发送到每个线程(一次只发送一个线程)?请向我解释一下,我真的很想了解这个过程。这是一个&#34;示例&#34;(似乎我无法发布图片):
        2. 服务*(发送)

          >  >> Server Started
          >  >> Client Connected
          >  >> Data Transfer Established
          >  >> Client Connected
          >  >> Data Transfer Established
          >  >> Client Connected
          >  >> Data Transfer Established
          .
          1 
          2 
          3
          4
          5
          6
          

          客户端1 (接收)

           >> Client Started
           >> Client Connected
          1
          4
          

          客户端2 (接收)

           >> Client Started
           >> Client Connected
          2
          5
          

          客户端3 (接收)

           >> Client Started
           >> Client Connected
          3
          6
          
          1. 如何将服务器收到的数据发送给所有客户?

          2. 我如何存储它们?究竟要存储(以及什么)能够通知服务器此客户端ID想要将数据发送到X客户端ID。 (例如:客户1想说&#34;我在沙滩上&#34;到客户3和&#34;我在家&#34;到客户2)

          3. / *我知道可能会出现很多因为我没有编程如此防守,但现在我只想学习并且对我来说任何可能出现的例外都有帮助。而且我知道Flush的第一个流不会到达,但在这种情况下我可能做错了,因为我正在调查这个问题。 * /

            / *值得一提的是:客户只与服务器聊天,他们不会看到其他客户写的内容。并且服务器以正确的顺序接收数据* /

            P.S。如果您对此问题感兴趣,请使用此代码。我来到这里是因为我想学习这些东西不是因为我搜索了另一个&#34;技巧&#34;或者只是解决它。

2 个答案:

答案 0 :(得分:0)

当客户端连接到服务器时,将客户端添加到集合中。当服务器接收到需要传递给所有其他连接客户端的数据时,迭代客户端集合并向其发送数据。您需要检查客户端是否仍然连接。向所有连接的客户端广播消息比私有消息传递更容易。您只需将消息从一个客户端重播到所有客户端,如上所述。对于私人消息传递,客户端需要向服务器发送命令,这表明客户的意图。例如,一个简单的命令可能是

发送&#34;你好约翰&#34;致客户3

答案 1 :(得分:0)

我会尽力回答这些问题:

首先,您应该在代码中正确添加更多调试消息,因为这将极大地帮助您理解该过程。这是一个pastebin,我修改了你的代码以包含更多的消息,这样你就可以更好地理解读/写的内容。

  

服务器为什么或者可能“如何”将数据发送到每个线程(到   一次只有一个线程)按照它们的创建顺序?请   向我解释一下,我真的很想了解这个过程。这里有一个   “样本”(似乎我无法发布图片):

服务器不向每个线程发送数据。它将数据发送到由tcpC.GetStream()检索的Streams。在acceptClients函数中,您将获得该特定客户端(连接的客户端)的网络流。然后,将这些传递给您创建的新线程。然后,每个读/写线程对都可以访问自己的NetworkStream以便与客户端一起工作。

您被混淆的原因是因为您使用其他客户端的值覆盖tcpCnStream。变量tcpCnStream应该是一个List。对于连接的每个客户端,有TcpClientNetworkStream

换句话说。在服务器上,对于您运行的每个客户端,有1 TcpClient,1 NetworkStream和2 Threads

  

如何将服务器收到的数据发送给所有客户端?

您要做的是向所有客户收到的广播信息(如聊天程序)。为此,您需要List<string>作为缓冲区。您将在doReading函数中的服务器上读取一个列表(缓冲区),它将存储您从客户端读取的内容。然后,您将使用doWriteing函数将该列表写入客户端。您还需要一种方法来确保服务器向所有客户端发送消息(而不仅仅是其中一个消息)。

  

客户1希望向客户3说“我在沙滩上”

为此,您需要一种以命令行格式说明的方法。像

这样的东西
SEND ID TEXT

ID是您希望发送的客户端#,其后是消息。然后,您还可以使用BROADCAST TEXT之类的内容向所有客户广播。

再次使用Pastebin链接:http://pastebin.com/SBjc6tBF