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

时间:2016-03-31 21:46:49

标签: c# sockets tcp tcpclient networkstream

我试图建立一个可以在彼此之间来回读写信息的客户端和服务器。我可以从客户端和服务器写入读取但不反之亦然,我不知道为什么。这里的任何人似乎都不知道我以前什么时候问过,而且我在网上找不到任何有用的东西。如果您知道,请告诉我,不要告诉我去阅读有关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;}
    }
}
}
}

Receiver / Server:

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:未设置对象引用到一个对象的实例。在exampleserver.form1.receive()"。

3 个答案:

答案 0 :(得分:1)

您的客户从未收到回复的问题是由于您从未接受过。

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

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

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

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

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

  1. 读取消息的长度(字节数)
  2. 将长度存储在整数中。
  3. 选择标题(通常只需一个字节的标题)。
  4. 将长度与标题连接,然后与消息的其余部分连接。
  5. 这将产生以下结构:

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

    阅读:

    1. 读取前4个字节,并将返回的数组转换为Integer。
    2. 读取下一个字节以获取标题。
    3. 阅读,直到您阅读了整条信息。根据标题确定您对邮件的处理方式。
    4. 阅读该序列,您将始终知道从另一个端点读取和期望的内容,因此您不会遇到部分或消息被集中在一起的问题。

      希望这有帮助!

答案 1 :(得分:0)

每个套接字地址(协议/网络地址/端口)通常只允许使用一种...不要启动TcpListener。

答案 2 :(得分:-1)

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

你捕获了第一个NullReferenceException,但是在catch中,你再次调用Writer,抛出一个新的。{/ p>