TCP从客户端和服务器读取和写入

我正在尝试创建一个可以在彼此之间来回读写信息的客户端和服务器。 我可以从客户端和服务器写入读取但不反之亦然,我不知道为什么。 这里似乎没有人知道我之前问过什么,而且我无法在网上找到任何有用的东西。 如果您知道请告诉我,不要告诉我去阅读有关TCP的文章,因为它根本没有用。

客户:

namespace ExampleClient { public partial class Form1 : Form { public static bool IsConnected; public static NetworkStream Writer; public static NetworkStream Receiver; public Form1() { InitializeComponent(); } private void BtnConnect_Click(object sender, EventArgs e) { TcpClient Connector = new TcpClient(); Connector.Connect(TxtIP.Text, Convert.ToInt32(TxtPort.Text)); IsConnected = true; Writer = Connector.GetStream(); Console.WriteLine("Connected"); System.Threading.Thread Rec = new System.Threading.Thread(new System.Threading.ThreadStart(Receive)); Rec.Start(); } private void BtnWrite_Click(object sender, EventArgs e) { try{ byte[] Packet = Encoding.ASCII.GetBytes("Client Write Test"); Writer.Write(Packet, 0, Packet.Length); Writer.Flush();} catch{ try { Writer.Close();} catch { }} } public static void Receive() { while (true){ try{ byte[] RecPacket = new byte[1000]; Receiver.Read(RecPacket, 0, RecPacket.Length); Receiver.Flush(); string Message = Encoding.ASCII.GetString(RecPacket); MessageBox.Show(Message); } catch { break;} } } } } 

接收器/服务器:

 namespace ExampleServer { public partial class Form1 : Form { public static NetworkStream Writer; public static NetworkStream Receiver; public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { TcpListener Server = new TcpListener(2002); Server.Start(); TcpClient Connection = Server.AcceptTcpClient(); Receiver = Connection.GetStream(); System.Threading.Thread Rec = new System.Threading.Thread(new System.Threading.ThreadStart(Receive)); Rec.Start(); } public static void Receive() { while (true) { try { byte[] RecPacket = new byte[1000]; Receiver.Read(RecPacket, 0, RecPacket.Length); Receiver.Flush(); string Message = Encoding.ASCII.GetString(RecPacket); MessageBox.Show(Message); try{ byte[] Packet = Encoding.ASCII.GetBytes("Server Write Test"); Writer.Write(Packet, 0, Packet.Length); Writer.Flush();} catch{ try { Writer.Close(); } catch { }} } catch { break; } } } } } 

因此,当服务器从客户端读取消息时,它会显示它正常工作,但是当它将消息写回客户端时,它会崩溃并显示错误“system.nullreferenceeexception:对象引用未设置为对象的实例.atampleserver.form1.receive()“。

客户端永远不会收到响应的问题是由于您从未接受过。

你永远不会初始化客户端的Receiver流,应用程序没有破坏,因为A)错误被抛出在另一个线程中, B)你只是在发生错误时打破while循环,你真的需要以某种方式记录错误。

仅使用一个NetworkStream 。 该流支持同时接收和发送,并且只有两个以上更容易 – 您不会忘记轻松初始化它。

在将来,您还应该考虑处理您的消息。 由于TCP是基于流的,因此您可以以任何可能的方式获取消息; 消息的三分之一,消息的一半,或一次只有一个字节(等)。 有几种方法可以解决这个问题,但最好的方法是长度前缀 (或长度前缀 )。

长度前缀与标头前缀相结合,使您的消息在接收正确信息时可靠。 如果操作正确,您始终可以确保收到包含正确且正确数据量的消息。

长度和标头前缀意味着您为每条消息添加正确的长度前缀 ,以及一个标题,告诉消息的用途。 这就是它的组成方式:

  1. 读取消息的长度(字节数)
  2. 将长度存储在整数中。
  3. 选择一个标题(通常一个字节的标题就足够了)。
  4. 将长度与标题连接,然后与消息的其余部分连接。

这将产生以下结构:

 [Length (4 bytes)][Header (1 byte)][Message (?? byte(s))] 

阅读它:

  1. 读取前4个字节,并将返回的数组转换为Integer。
  2. 读取下一个字节以获取标题。
  3. 阅读,直到您阅读完整个消息长度。 根据标题确定您对邮件的处理方式。

读取该序列,您将始终知道从另一个端点读取和期望多少,因此您不会遇到部分或消息被集中在一起的问题。

希望这可以帮助!

我不认为你正在初始化Writer 。 确保在调用之前初始化。

你捕获第一个NullReferenceException,但是然后在catch中,你再次调用Writer ,抛出一个新的。