2013-11-10 96 views
0

我新在C#中的多线程和我从下面的教程在网上遇到过这个问题多线程TCPSERVER不能正常工作

这是我的服务器

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Net; 
using System.Net.Sockets; 
using System.Configuration; 
using System.Threading; 

namespace CoreEngine 
{ 
    class MultithreadedTCP 
    { 
     private TcpListener myListener; 
     private Thread ListenThread; 

    public MultithreadedTCP() 
    { 
     IPAddress ip = IPAddress.Parse(ConfigurationManager.AppSettings["CoreEngineIP"]); 
     myListener = new TcpListener(ip, Convert.ToInt32(ConfigurationManager.AppSettings["CoreEnginePort"])); 
     this.ListenThread = new Thread(new ThreadStart(ListenForClients)); 
     this.ListenThread.Start(); 
    } 

    private void ListenForClients() 
    { 
     this.myListener.Start(); 

     while (true) 
     { 
      TcpClient client = this.myListener.AcceptTcpClient(); 
      Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm)); 
      clientThread.Start(client); 
     } 
    } 

    private void HandleClientComm(object client) 
    { 
     TcpClient Tcpclient = (TcpClient)client; 
     NetworkStream clientStream = Tcpclient.GetStream(); 
     byte[] message = new byte[4096]; 
     while (true) 
     { 
      //send all data here 
      clientStream.Read(message, 0, message.Length); 
      Console.WriteLine("client connected : " + Encoding.UTF8.GetString(message, 0, message.Length)); 
      //break; 
     } 

    } 
} 

}

这是我的客户端代码。我刺激4客户机连接到该服务器

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Net; 
using System.Net.Sockets; 
using System.IO; 
using System.Configuration; 
using System.Configuration.Assemblies; 
namespace WindowsFormsApplication1 
{ 
    class Client 
    { 
     public void send(String args) 
     { 
      TcpClient tcp = new TcpClient(); 
      TcpClient tcp1 = new TcpClient(); 
      TcpClient tcp2 = new TcpClient(); 
      TcpClient tcp3 = new TcpClient(); 
      tcp.Connect(ConfigurationManager.AppSettings["CoreEngineIP"], Convert.ToInt32(ConfigurationManager.AppSettings["CoreEnginePort"])); 
      tcp1.Connect(ConfigurationManager.AppSettings["CoreEngineIP"], Convert.ToInt32(ConfigurationManager.AppSettings["CoreEnginePort"])); 
      tcp2.Connect(ConfigurationManager.AppSettings["CoreEngineIP"], Convert.ToInt32(ConfigurationManager.AppSettings["CoreEnginePort"])); 
      tcp3.Connect(ConfigurationManager.AppSettings["CoreEngineIP"], Convert.ToInt32(ConfigurationManager.AppSettings["CoreEnginePort"])); 

      args = "client 0"; 
      Stream str = tcp.GetStream(); 
      ASCIIEncoding asen = new ASCIIEncoding(); 
      byte[] b = asen.GetBytes(args); 
      str.Write(b, 0, b.Length); 

      args = "client 1"; 
      Stream str1 = tcp1.GetStream(); 
      ASCIIEncoding asen1 = new ASCIIEncoding(); 
      byte[] b1 = asen.GetBytes(args); 
      str.Write(b1, 0, b.Length); 

      args = "client 2"; 
      Stream str2 = tcp2.GetStream(); 
      ASCIIEncoding asen2 = new ASCIIEncoding(); 
      byte[] b2 = asen.GetBytes(args); 
      str.Write(b2, 0, b.Length); 

      args = "client 3"; 
      Stream str3 = tcp3.GetStream(); 
      ASCIIEncoding asen3 = new ASCIIEncoding(); 
      byte[] b3 = asen.GetBytes(args); 
      str.Write(b3, 0, b.Length); 
     } 
    } 
} 

输出:客户端连接:客户端0客户端1个客户端2客户端3

预期输出: 客户端已连接:客户端0 客户端已连接:客户端1个 客户端连接:客户端2 客户端连接:客户端3

回答

1

您在每个块中调用第一个客户端str.Write

但是,这表明你没有考虑的第二个问题,Read(不读取相同数量的Write(放在电线上。所有4条连接消息合并到一个Read

您需要开发某种形式的“消息协议”来表示一个消息停止和一个消息开始的位置。最简单的方法是在发送消息之前预先填写消息的长度。

客户端

args = "client 0"; 
Stream str = tcp.GetStream(); 
ASCIIEncoding asen = new ASCIIEncoding(); 
byte[] b = asen.GetBytes(args); 
if(b.Length > 255) 
    throw new InvalidDataException("Messages must have a length less than 256"); 
str.WriteByte((byte)b.Length); 
str.Write(b, 0, b.Length); 

服务器端

byte[] message = new byte[256]; //This can now be 256 as that is the most messageLength can be. 
while (true) 
{ 
    //get the length of the message 
    int messageLength = clientStream.ReadByte(); 
    if(messageLength == -1) 
     break; 

    // "Read(" can read less than the total length you requested, so you must loop till you have the entire message. 
    int offset = 0; 
    while(offset < messageLength) 
    { 
     offset += clientStream.Read(message, offset, messageLength - offest); 
    } 
    Console.WriteLine("client connected : " + Encoding.UTF8.GetString(message, 0, message.Length)); 
} 

如果你想送比你可以,但你需要设计围绕该protocal 255个字节的消息。例如,您可以从客户端写入网络流str.Write(BitConverter.GetBytes(b.Length), 0, 4),并读取消息的前4个字节,然后调用int messageLength = BitConverter.ToInt32(message),但在开始使用多字节数字时,您需要开始担心Endianness。 (BitConverter.IsLittleEndian总是会在Windows桌面上返回true,但在移动平台上可能会有所不同)

+0

非常感谢您指出这一点!傻我 – aceminer

+0

@aceminer如果我解决了你的问题,请将答案标记为已接受。 –

+0

是的,但我不能,因为时间限制还没有到。现在做了 – aceminer