求大大神指点TCP长连接传输数据如何不掉线的问题

m0_37578846 2017-03-16 12:19:04
本人是一个C#初学者,最新因工作要求写一个基于C#服务端与客户端TCP连接传输数据的程序,突击似的在论坛各位大神的文章和技术指导,自己写了一个初步的程序,数据传输正常,但是总是不定时的出现接收数据线程停在那里不动了,也不会重新连接。了解到需要利用心跳包机制保持连接状态,但是看了些文章总是不知道如何用到自己程序中,恳请各位大神针对我的程序给出详细的指导最好有注释。下面贴出我的程序源码!
程序功能介绍:
客户端采集本地设备数据,每采集2分钟后的数据通过tcpclient传输到服务端。
服务端采集本地设备数据,每采集2分钟后在与接收的客户端数据进行合并,然后保存TXT为分析准备。
所以需要客户端每2分钟向服务端传输数据,因此实时性要求比较高而且是连续不断的进行周期传输。

//客户端传输代码
TcpClient client;
NetworkStream netstream;
private string ServerIP; //IP
private int port; //端口
private bool isExit = false;
private BinaryReader br;
private BinaryWriter write22;
private IPEndPoint ipe;
//初始化TCP通道,这里我简化了只贴出有用的
private void SetServerIPAndPort()
{
try
{
ServerIP = "173.57.136.91"; //设定IP
port =“8092”; //设定端口
}
catch (Exception ex)
{
Log_output("配置IP与端口失败,错误原因:" + ex.Message);
Application.Exit();
}
}

//与服务端建立连接
private void ServerConnect()
{
try
{

client = new TcpClient();
ipe = new IPEndPoint(IPAddress.Parse(ServerIP), port);
client.Connect(ipe);
netstream = client.GetStream();//获取网络流
if (!((client.Client.Poll(1000, SelectMode.SelectRead) && (client.Client.Available == 0)) || !client.Client.Connected))
{
Thread send = new Thread(sendData);//启动发送数据线程
send.Start();
Log_output("与服务端连接成功");//运行日志
btstart();//连接服务端成功后开始采集数据
m = 0; //采集数据计时器120次完成一个采集周期开始发送数据
l = 0;//记录每个周期采集开始的时间
}
else
{
//设置连接失败后再尝试连接4次,再失败显示人工连接按钮
if (bzw < 3)
{
bzw++;
ServerConnect();//连接失败,继续尝试连接
}
else
{
button2.Visible = true;
}
}
}
//向服务端发生数据的线程
private void sendData()
{
while (true)
{
try
{
if (m > 119)//采集周期完成才能发送数据
{

BinaryFormatter Formatter = new BinaryFormatter();
pass_data_PQT1[0, 120000] = input_T1;//在数组里写入时间戳,两边数据同步准备的可忽略了解
pass_data_PQT1[1, 120000] = input_T1;
pass_data_PQT1[2, 120000] = input_T1;

Formatter.Serialize(netstream, pass_data_PQT1);
byte[] bytes = new byte[120000];

netstream.Write(bytes, bytes.Length, 0); //发送数据
netstream.Flush();//网络流刷新
btStop();//停止采集数据,等待服务端接收数据回应后在同步开始采集
m = 0; //采集周期计时位
}
//下面是为了得到服务端接收数据完成后的回应
if (client.Client.Poll(10000, SelectMode.SelectRead))
{
if (client.Available > 0)
{
br = new BinaryReader(netstream);
string receiveString = br.ReadString();
string[] splitString = receiveString.Split(',');
bool exists = ((IList)splitString).Contains("1111");

if (exists)//如果得到回应我就开始下个周期采集
{
l = 0;
Log_output("接收到服务回应,发送数据成功!");
btstart();
}
else//如何没有回应我准备重新连接下服务端,可是这个连接感觉没什么用
{
m = 0;
l = 0;
btStop();
Log_output("未收到服务回应,发送数据失败!");
this.Invoke((EventHandler)(delegate
{
ServerConnect();
}));
break;
}
}
}
}
catch (Exception ex)//这是也是出现异常后,想重新连接服务端
{
m = 0;
l = 0;
btStop();
//netstream.Close();
Log_output("数据流不可写入,重新采集!"+ex.ToString());
this.Invoke((EventHandler)(delegate
{
ServerConnect();
}));
Thread.Sleep(5000);
break;
}
}
...全文
631 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
编程有钱人了 2017-03-17
  • 打赏
  • 举报
回复
yahle 2017-03-17
  • 打赏
  • 举报
回复
引用 16 楼 xian_wwq 的回复:
[quote=引用 13 楼 m0_37578846 的回复:] [quote=引用 11 楼 wddw1986 的回复:] 如果你只是简单的传输一点数据,根本没必要自己做通信逻辑,使用成型的东西最好。 http上传,web api,都是简单的实现方式
我觉得传输量还是挺大,每个周期传输12万条数据。要循环周期的采集然后两端数据实时合并[/quote] 11楼说的也在理, 不知道每笔数据是多大, 如果按照每笔数据30个字节,那么 12万*30/1024/1024 约3.5M 2分钟的周期内发送3.5M的数据真的不算大。 [/quote] 一个服务端会对接几个客户端?
m0_37578846 2017-03-16
  • 打赏
  • 举报
回复
系统帖子不要沉,各位大神帮帮忙!谢谢
m0_37578846 2017-03-16
  • 打赏
  • 举报
回复
这是 服务端代码 //服务端程序代码 TcpClient newClient = null; Socket cilentSocket;//作为客户端的套接字 Socket serverSocket; TcpClient client; TcpListener server; NetworkStream stream; User user; //建立监听 private void Start_sockerConnectClient() { try{ myListener = new TcpListener(IPAddress.Any, port); myListener.Start(); Log_output("启动监控成功!"); } catch(Exception ex) { myListener.Stop(); Log_output("建立监听异常,原因:"+ex.ToString()); } AddItemToListBox(string.Format("开始在{0}:{1}监听客户连接", serverip, port)); //创建一个线程监客户端连接请求 Thread myThread = new Thread(ListenClientConnect); myThread.Start(); flag_Net = true; } //接收客户端连接请求的线程 private void ListenClientConnect() { while (flag_Net == true) { try { newClient = myListener.AcceptTcpClient(); user = new User(newClient); string userstr = newClient.Client.RemoteEndPoint.ToString(); user.userName = userstr.Split(':')[0]; //设定IP client = user.client; stream = client.GetStream();//获取网络流 Thread threadReceive = new Thread(receiveData2);//启动接收数据的线程 threadReceive.Start(user); flag_start = true; userList.Add(user);//增加到用户列表中 this.Invoke((EventHandler)(delegate { Log_output(string.Format("当前连接用户数:{0}", userList.Count + "," + userList[0].userName)); label125.Text = "正 常"; label125.ForeColor = Color.White; m = 0; l = 0; btstart();//接收到客户端请求后 ,开始采集本地设备数据 })); } catch(Exception ex)//异常后想重新监听,这里估计我写的也不对求指导 { flag_Net = false; Start_sockerConnectClient(); this.Invoke((EventHandler)(delegate { Log_output("接收客户端" + ex.ToString()); })); } } } } //接收客户端发来的数据线程,并回应客户端接到数据 private void receiveData2(object userState) { user = (User)userState; while (true) { if (flag_start == true) { try { if (stream.DataAvailable && m > 119)//这里也是判断有数据可读,并且本地采集周期完成 { btn_stop();//停止采集,接收完成后在同步采集 BinaryFormatter Formatter = new BinaryFormatter(); double[,] pass_data_PQT10 = (double[,])Formatter.Deserialize(stream); int leng = pass_data_PQT10.Length; input_T2 = pass_data_PQT10[0, 120000]; Log_output("接收到数据"); //这里是数组转换可忽略 for (int i = 0; i < 2; i++) { for (int j = 0; j < 120000; j++) { pass_data_PQT2[i, j] = pass_data_PQT10[i, j]; } } SendToClient(user, "1111");//接收到数据后,给客户端回应 CutOutTime(pass_data_PQT1, pass_data_PQT2); //为数据加入时间,并进行时间同步 l = 0; m = 0; btstart();//开始下个周期采集数据 } else { } } catch (Exception ex)//这里本意也是异常后重新监听客户端,可是每次掉线并不会出现异常,就好像这个线程假死了一样 { btServerstop(); l = 0; m = 0; flag_start = false; ListenClientConnect();//启动监听客户端连接 Log_output("接收数据异常,原因:" + ex.ToString()); Thread.Sleep(50000); } } } } //异常后删除当前接收客户端的对象 private void btServerstop() { // AddItemToListBox("开始停止服务,并依次使用户退出!"); isNormalExit = true; for (int i = userList.Count - 1; i >= 0; i--) { RemoveUser(userList[i]); } myListener.Stop(); }
xian_wwq 2017-03-16
  • 打赏
  • 举报
回复
server侧的数据接收和数据解析必须分离, 否则压力大了,server就不可用了 网络通信模块只负责接收数据,把数据放到线程安全的容器(必须队列)中立即返回; 数据解析可以使用线程池或者任务。
xian_wwq 2017-03-16
  • 打赏
  • 举报
回复
引用 13 楼 m0_37578846 的回复:
[quote=引用 11 楼 wddw1986 的回复:] 如果你只是简单的传输一点数据,根本没必要自己做通信逻辑,使用成型的东西最好。 http上传,web api,都是简单的实现方式
我觉得传输量还是挺大,每个周期传输12万条数据。要循环周期的采集然后两端数据实时合并[/quote] 11楼说的也在理, 不知道每笔数据是多大, 如果按照每笔数据30个字节,那么 12万*30/1024/1024 约3.5M 2分钟的周期内发送3.5M的数据真的不算大。
m0_37578846 2017-03-16
  • 打赏
  • 举报
回复
各位,大神,能否针对我的代码提些具体修改建议,我就结贴给分了。谢谢
m0_37578846 2017-03-16
  • 打赏
  • 举报
回复
引用 12 楼 xian_wwq 的回复:
数据连接,发送放在线程中, 主要是为了避免主线程被阻塞 出现UI无响应的情况, 和连接是否是长连接无关 ---- 如果你的server只接收一路,那sp大神的提醒可以忽略 只要并行处理超过1个,那6楼指出的问题必须解决
对就是点对点传输,没其他的
m0_37578846 2017-03-16
  • 打赏
  • 举报
回复
引用 11 楼 wddw1986 的回复:
如果你只是简单的传输一点数据,根本没必要自己做通信逻辑,使用成型的东西最好。 http上传,web api,都是简单的实现方式
我觉得传输量还是挺大,每个周期传输12万条数据。要循环周期的采集然后两端数据实时合并
xian_wwq 2017-03-16
  • 打赏
  • 举报
回复
数据连接,发送放在线程中, 主要是为了避免主线程被阻塞 出现UI无响应的情况, 和连接是否是长连接无关 ---- 如果你的server只接收一路,那sp大神的提醒可以忽略 只要并行处理超过1个,那6楼指出的问题必须解决
cheng2005 2017-03-16
  • 打赏
  • 举报
回复
如果你只是简单的传输一点数据,根本没必要自己做通信逻辑,使用成型的东西最好。 http上传,web api,都是简单的实现方式
m0_37578846 2017-03-16
  • 打赏
  • 举报
回复
引用 7 楼 xian_wwq 的回复:
服务端(Server)侦听一次就行了, 如果是短连接,那么客户端每次的流程都是:连接-发送-断开 如果是长连接,那么client侧的重连逻辑要足够健壮, 同时server侧必须对连接客户端进行超时检测, 及时清理非正常状态的客户端连接, 否则server有资源被耗尽的可能。 为了维持长链路,需要在链路空闲时,定时发送心跳包,以维持链路, 否则server不处理超时,相关网络设备也会定期清理空闲链路。 要保证可靠传输,最好有应答机制, client发送完成后,接收到server的应答包,才能真正保证数据传输完成。 网络通信需要处理的异常情况比较多, 比如客户端退出,服务侧可能监测到,也可能监测不到 比如连接、传输环节的超时等,都需要处理。
还有个问题,就是短连接是不是就不需要写进线程里了,直接方法即可?
m0_37578846 2017-03-16
  • 打赏
  • 举报
回复
引用 7 楼 xian_wwq 的回复:
服务端(Server)侦听一次就行了, 如果是短连接,那么客户端每次的流程都是:连接-发送-断开 如果是长连接,那么client侧的重连逻辑要足够健壮, 同时server侧必须对连接客户端进行超时检测, 及时清理非正常状态的客户端连接, 否则server有资源被耗尽的可能。 为了维持长链路,需要在链路空闲时,定时发送心跳包,以维持链路, 否则server不处理超时,相关网络设备也会定期清理空闲链路。 要保证可靠传输,最好有应答机制, client发送完成后,接收到server的应答包,才能真正保证数据传输完成。 网络通信需要处理的异常情况比较多, 比如客户端退出,服务侧可能监测到,也可能监测不到 比如连接、传输环节的超时等,都需要处理。
谢谢,心跳检测的代码网络上看了些,还是不太清楚怎么用起来,不行我就试试短连接,短连接就是每次客户端发完断开,服务端需要操作吗?是不是就剔除当前连接的用户即可?
m0_37578846 2017-03-16
  • 打赏
  • 举报
回复
引用 5 楼 m0_37578846 的回复:
上面有些文字表述错误,是对含义不明确!
呵呵,谢谢指出,大的概念懂些,就是实现起来逻辑不清晰,我也觉得问题多,如果有时间希望能多给找出些问题。谢谢!
xian_wwq 2017-03-16
  • 打赏
  • 举报
回复
服务端(Server)侦听一次就行了, 如果是短连接,那么客户端每次的流程都是:连接-发送-断开 如果是长连接,那么client侧的重连逻辑要足够健壮, 同时server侧必须对连接客户端进行超时检测, 及时清理非正常状态的客户端连接, 否则server有资源被耗尽的可能。 为了维持长链路,需要在链路空闲时,定时发送心跳包,以维持链路, 否则server不处理超时,相关网络设备也会定期清理空闲链路。 要保证可靠传输,最好有应答机制, client发送完成后,接收到server的应答包,才能真正保证数据传输完成。 网络通信需要处理的异常情况比较多, 比如客户端退出,服务侧可能监测到,也可能监测不到 比如连接、传输环节的超时等,都需要处理。
  • 打赏
  • 举报
回复
代码的问题很多很多、很多。不过只说一个对你来说最“近”的吧,你的 stream 变量设置为共享的,那就意味着各个线程原本应该独立操作的对象被胡乱覆盖,只能有一个“接收”通道真正成功。
m0_37578846 2017-03-16
  • 打赏
  • 举报
回复
上面有些文字表述错误,是对含义不明确!
m0_37578846 2017-03-16
  • 打赏
  • 举报
回复
引用 3 楼 xian_wwq 的回复:
”需要客户端每2分钟向服务端传输数据,因此实时性要求比较高而且是连续不断的进行周期传输。“ 传输周期2分钟,不能算作实时性要求高, 个人认为可以不使用长连接。 这样处理逻辑可以简化,Server侧的管理也就相对简单。
您的意识是我每次需要发送数据时再建立连接,传输完数据就关闭?其实我对长短连接和同步异步含义还是十分明确,我说的实时性就是我发送的数据服务端能马上接收到,好方便下个周期同步采集。短连接的话服务端的监听要不要每次都重新启动?还有每次关闭当前连接时都关闭哪些对象和顺序也不明确。能否给个具体代码或者文字步骤的描述?谢谢
xian_wwq 2017-03-16
  • 打赏
  • 举报
回复
”需要客户端每2分钟向服务端传输数据,因此实时性要求比较高而且是连续不断的进行周期传输。“ 传输周期2分钟,不能算作实时性要求高, 个人认为可以不使用长连接。 这样处理逻辑可以简化,Server侧的管理也就相对简单。

110,526

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧