C# TcpClient 未发送或读取 100% 的数据?
嘿大家。我正在编写一个简单的客户端/服务器应用程序(只是为了体验,网络对我来说相当新),其中客户端发送服务器数据,服务器将其输出到文本框。除了一个小细节之外,一切都工作正常......有时似乎建立了连接,但数据没有被发送或读取(无法弄清楚是哪个),因此文本框中没有输出任何内容。每次建立连接时,计数器都会递增,收到数据块时也是如此。当您比较两者时,连接数是正确的,但数据计数器通常较低,有时多达一半。无论如何,如果有人能给我一些建议或指出我正确的方向,我将不胜感激!
如果您需要,这里是代码:
(SERVER_CODE)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace Server
{
public partial class Form1 : Form
{
public int Connections = 0;
public int blocks = 0;
public int threads = 0;
public Thread MasterThread;
public TcpListener Master;
public volatile bool Run;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
public void StartMaster()
{
Master = new TcpListener(IPAddress.Any, 1986);
Master.Start();
MasterThread = new Thread(new ThreadStart(RunMaster));
MasterThread.Start();
}
public void RunMaster()
{
threads++;
label6.Text = String.Format("{0}", threads);
while (Run)
{
TcpClient client = Master.AcceptTcpClient();
Connections++;
label4.Text = String.Format("{0}", Connections);
Thread ClientThread = new Thread(new ParameterizedThreadStart(RunClient));
ClientThread.Start(client);
}
Master.Stop();
threads--;
label6.Text = String.Format("{0}", threads);
}
public void RunClient(object tcpClient)
{
TcpClient client = (TcpClient)tcpClient;
byte[] buffer = new byte[4096];
int byteCount = 0;
NetworkStream stream = client.GetStream();
threads++;
label6.Text = String.Format("{0}", threads);
while (Run)
{
try
{
byteCount = stream.Read(buffer, 0, 4096);
}
catch
{
//Connections--;
break;
}
if (byteCount == 0)
{
//Connections--;
break;
}
blocks++;
label5.Text = String.Format("{0}", blocks);
textBox1.AppendText(Encoding.ASCII.GetString(buffer, 0, byteCount) + "\r\n");
}
client.Close();
threads--;
label6.Text = String.Format("{0}", threads);
}
private void button1_Click(object sender, EventArgs e)
{
Run = true;
StartMaster();
}
private void button2_Click(object sender, EventArgs e)
{
Run = false;
}
}
}
(CLIENT_CODE)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace Client
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1986);
TcpClient client = new TcpClient();
try
{
client.Connect(endPoint);
}
catch
{
MessageBox.Show("Connect Error");
}
NetworkStream stream = client.GetStream();
byte[] data = Encoding.ASCII.GetBytes(textBox1.Text);
stream.Write(data, 0, data.Length);
stream.Flush();
client.Close();
}
}
}
谢谢,
特里斯坦!
Hey all. I'm writing a simple client/server application (just for the experience, networking is fairly new to me) where the client sends the server data and the server outputs it to a textbox. It all works fine, except for one small detail... It seems sometimes a connection is made, but the data isn't being sent or read (can't work out which) and thus nothing is being outputted in the textbox. Every time a connection is made a counter is incremented, same thing when a data block is received. When you compare the two, the number of connections is correct but the data counter is usually lower, sometimes by as much as half. Anyway, if anyone can give me some advice or point me in the right direction, it would be greatly appreciated!
Here's the code if you require it:
(SERVER_CODE)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace Server
{
public partial class Form1 : Form
{
public int Connections = 0;
public int blocks = 0;
public int threads = 0;
public Thread MasterThread;
public TcpListener Master;
public volatile bool Run;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
public void StartMaster()
{
Master = new TcpListener(IPAddress.Any, 1986);
Master.Start();
MasterThread = new Thread(new ThreadStart(RunMaster));
MasterThread.Start();
}
public void RunMaster()
{
threads++;
label6.Text = String.Format("{0}", threads);
while (Run)
{
TcpClient client = Master.AcceptTcpClient();
Connections++;
label4.Text = String.Format("{0}", Connections);
Thread ClientThread = new Thread(new ParameterizedThreadStart(RunClient));
ClientThread.Start(client);
}
Master.Stop();
threads--;
label6.Text = String.Format("{0}", threads);
}
public void RunClient(object tcpClient)
{
TcpClient client = (TcpClient)tcpClient;
byte[] buffer = new byte[4096];
int byteCount = 0;
NetworkStream stream = client.GetStream();
threads++;
label6.Text = String.Format("{0}", threads);
while (Run)
{
try
{
byteCount = stream.Read(buffer, 0, 4096);
}
catch
{
//Connections--;
break;
}
if (byteCount == 0)
{
//Connections--;
break;
}
blocks++;
label5.Text = String.Format("{0}", blocks);
textBox1.AppendText(Encoding.ASCII.GetString(buffer, 0, byteCount) + "\r\n");
}
client.Close();
threads--;
label6.Text = String.Format("{0}", threads);
}
private void button1_Click(object sender, EventArgs e)
{
Run = true;
StartMaster();
}
private void button2_Click(object sender, EventArgs e)
{
Run = false;
}
}
}
(CLIENT_CODE)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace Client
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1986);
TcpClient client = new TcpClient();
try
{
client.Connect(endPoint);
}
catch
{
MessageBox.Show("Connect Error");
}
NetworkStream stream = client.GetStream();
byte[] data = Encoding.ASCII.GetBytes(textBox1.Text);
stream.Write(data, 0, data.Length);
stream.Flush();
client.Close();
}
}
}
Thank-you,
Tristan!.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
好吧,首先你会用这个来削弱你自己的诊断:
为什么你要在没有任何日志记录的情况下吞掉异常?也许抛出了异常,而您无从得知。理想情况下,您应该捕获特定异常,并且当您确实捕获异常时至少记录正在发生的情况。
另一方面,Wireshark 应该可以帮助您确定数据是否正在发送。
Well, to start with you're crippling your own diagnostics with this:
Why are you swallowing exceptions without any logging etc? Maybe an exception is being thrown, and you have no way of knowing. Ideally you should catch specific exceptions, and when you do catch an exception at least log what's going on.
At the other end of the spectrum, Wireshark should help you to work out whether the data is being sent or not.
我还没有彻底查看您的代码,但快速浏览后,您可以在没有适当锁定的情况下从多个线程访问变量。像
x++;
这样的语句必须读取x
的值,递增它,然后将其写回。现在,如果您有两个线程执行此操作,您可能会遇到这种情况:如果您需要从多个线程访问变量,请始终同步,除非您确切知道自己在做什么。例如,创建并使用如下所示的同步对象:
那么一次只有一个线程可以访问该变量,并且值会正确递增。
编辑:另一个问题是您从与创建可见控件的线程不同的线程访问可见控件。早期的 .NET 版本允许这样做,但较新的版本不允许。如果需要更新状态消息,则需要查看控件的
InvokeRequired
属性,如果设置为 true,则使用 Control.Invoke(...) 调用设置该属性的方法。I haven't had a thorough look at your code yet, but after a quick glance, you access variables from multiple threads without proper locking. A statement like
x++;
has to read the value ofx
, increment it, and write it back. Now if you have two threads doing this, you might run into this situation:If you need to access variables from multiple threads, ALWAYS synchronize unless you know exactly what you're doing. For example, create and use a synchronization object like this:
Then only one thread may access the variable at a time and values are incremented correctly.
Edit: Another problem is that you access visible controls from a different thread than the one that created them. Early .NET versions allowed this, but the newer don't. If you need to update status messages, you need to look at the control's
InvokeRequired
property and if set to true, use Control.Invoke(...) to call a method that sets the property.