请教一个C# TCP/IP通讯问题(WinForm)信息全,可供学习参考【高分】

lanserzhao 2011-08-23 03:57:56
全局参数:
Thread workthread;
Thread tLogin;
Thread tConnectToRemote;
Thread tRemoteSocketRead;

TcpClient remoteTcpClient=new TcpClient();
NetworkStream remoteNetStr;

private static bool RemoteIsLogin = false;
private static bool RemoteIsConnected = false;

Main_Load中(线程方式启动主程序StartWinMDT):
workthread = new Thread(new ThreadStart(StartWinMDT));
workthread.IsBackground = true;
workthread.Start();


StartWinMDT中:

tConnectToRemote = new Thread(new ThreadStart(tConnectToRemoteTcp)); //连接远程delphi socket 端口
tConnectToRemote.IsBackground = true;

tRemoteSocketRead = new Thread(new ThreadStart(RemoteCenterSocketRead));//开始监听远程 socket 内容
tRemoteSocketRead.IsBackground = true;

tLogin = new Thread(new ThreadStart(RemoteLogin)); 远程连接完成后 发送登录协议
tLogin.IsBackground = true;

tConnectToRemoteTcp(连接远程delphi socket 端口)中:

try
{
do
{
if (!RemoteIsConnected)
{
ConnectToRemote(); //连接远程 服务器
tRemoteSocketRead.Start(); //启动监听线程
if (RemoteIsConnected)
{
tLogin.Start();//如果成功连接后开始发送登录协议
}
}
Thread.Sleep(iConnectTime);
}
while (RemoteIsConnected);
}
catch { }
}



#region ConnectToRemote()与上级服务器建立连接
private bool ConnectToRemote()
{
bool p_rec = false;

try
{
remoteTcpClient.Connect(IPAddress.Parse(sRemoteHost), Int32.Parse(sRemotePort));
if (remoteTcpClient.Connected)
{
RemoteIsConnected = true;
remoteNetStr = remoteTcpClient.GetStream(); // 获取远程数据流到全局变量remoteNetStr
p_rec = true;
}
else
{
txbRemote.Text += "与上级服务器 " + sSName + " 的连接已经断开!";
Thread.Sleep(iConnectTime);
}
}
catch (Exception ex)
{
WriteTextBox(txbRemote, "与上级服务器 " + sSName + " 连接失败:" + ex.Message.ToString());
}
return p_rec;
}
#endregion


RemoteLogin中

private void RemoteLogin()
{
do
{
// Thread.Sleep(iWaitLoginTime);
if (remoteTcpClient.Connected && remoteNetStr!=null && remoteNetStr.CanWrite)
{
try
{
int intCoalLoginCount = 0;
for (int tmpi = 0; tmpi < CoalArray.Count; tmpi++)
{
if (Convert.ToBoolean(CoalArrayIfLogin[tmpi]) == false)
{
byte[] _SendRemoteLoginData = SendRemoteLoginData(Convert.ToInt32(CoalArray[tmpi]));
TcpSendToRemoteCenter(_SendRemoteLoginData, "20");
// SendRemoteLoginData与TcpSendToRemoteCenter 为组件登录协议包,为了不影响阅读没有贴上
Thread.Sleep(iWaitLoginTime);//LoadTime
}
if (Convert.ToBoolean(CoalArrayIfLogin[tmpi]))
intCoalLoginCount = intCoalLoginCount + 1;
}
if (intCoalLoginCount == CoalArray.Count) //已经全部登录
{
if (RemoteIsLogin == false)
WriteTextBox(txbRemote, "所有终端登录成功!!");
RemoteIsLogin = true;
}
}
catch (Exception ex)
{
WriteTextBox(txbRemote, "请求登录上级服务器" + sSName + "过程中失败:" + ex.Message.ToString());
}
}
Thread.Sleep(5000);
}
while (!RemoteIsLogin);
}



private void RemoteCenterSocketRead()
{
while (true)
{
if (remoteNetStr != null && remoteNetStr.CanRead)
{
int nsLen = 1024;
byte[] responseBuffer = new byte[nsLen];
int numberOfBytesRead = 0;
MemoryStream memStream = new MemoryStream();
try
{
do
{
numberOfBytesRead = remoteNetStr.Read(responseBuffer, 0, nsLen);
memStream.Write(responseBuffer, 0, numberOfBytesRead);
}
while (remoteNetStr.DataAvailable);
}
catch { }
byte[] buffer = TrimBytes(memStream.GetBuffer());
memStream.Dispose();
//处理远程响应回来内容,在此处对获取到的buffer 进行处理
}
else
{
try
{
if (remoteNetStr != null)
{
remoteNetStr.Dispose();
}
}
catch { }
finally
{
ConnectToRemote();
}
}
}// end while
}


现在的问题是 比如有10个终端,有什么原因可以造成登录不稳定,即有的成功,有的反复重发也不成功?注此程序为改写一基于delphi程序,和delphi程序相比,登录成功率低,求教可能原因,先谢了
...全文
2501 53 打赏 收藏 转发到动态 举报
写回复
用AI写文章
53 条回复
切换为时间正序
请发表友善的回复…
发表回复
terroQQ 2011-08-29
  • 打赏
  • 举报
回复
添加 log4net 记录日志,已经再分析日志也许能查找到原因.
另外你在处理buff时,是否有定义通讯协议?
codingtaoist 2011-08-29
  • 打赏
  • 举报
回复
排版看的眼花,你看看下面是不是有问题:
if (Convert.ToBoolean(CoalArrayIfLogin[tmpi]))
intCoalLoginCount = intCoalLoginCount + 1;
}
if (intCoalLoginCount == CoalArray.Count) //已经全部登录
当你循环这个登录过程的时候,对于第一次循环登录成功的,在第二次会重复计数intCoalLoginCount = intCoalLoginCount + 1;这样就使intCoalLoginCount == CoalArray.Count成立,从而使之前部分没登录成功也不再重新登录了。
方应看 2011-08-29
  • 打赏
  • 举报
回复
顶者有分。
henry-qu 2011-08-26
  • 打赏
  • 举报
回复
http://msdn.microsoft.com/zh-cn/library/fx6588te(v=VS.80).aspx
java201111 2011-08-26
  • 打赏
  • 举报
回复
对多线程编程,提供个人的调试经验:
1.每个线程定义一个序号,此序号是递增的。
代码中多用print(线程序号 + “正在做什么...”)来做跟踪。print最好是改用日志如log4net。

2.先在dos中测试核心模块后,再考虑gui的结合。
java201111 2011-08-26
  • 打赏
  • 举报
回复
太多的线程,粗看了一遍代码,整个大脑都是异步+状态,看的很累,特别是Thread workthread; Thread tLogin; Thread tConnectToRemote; Thread tRemoteSocketRead;这四个线程,感觉有很重的坏味道,发觉自己是外星人一样,不知道是不是socket编程有没有这样的写法。因此斗胆说下自己的观点:楼主或团队应该没有socket编程经验,建议看看最经典的阻塞式或异步模型的代码。

socke编程如果性能不作要求的话,建议采用阻塞式编程,不要用什么异步模型,从代码中看,楼主走都不会,就想跑,最后导致bug难以跟踪。

socket本人只写过移动,电信,联通的短信网关,经验也不丰富。我曾经维护过JAVA写的短信网关程序,就是用阻塞式,也没感到性能很低。去年用c#也写了过短信网关,用异步模型,感觉难度比阻塞式大些。

根据楼主的代码,整理了以下思路仅供参考

全局变量登陆次数(这个变量的定义只供参考,根据需求来处理,需要考虑加锁)

socket线程:
for(){
全局变量登陆次数 >10
本线程终止
}
连接服务器
打开数据流
for(;;){
阻塞(具体语法问google)
发送数据包(此处是主要的业务逻辑,如发送登陆包)
全局变量登陆次数++
}
关闭数据流

主线程:
socket线程.启动

lanserzhao 2011-08-25
  • 打赏
  • 举报
回复
[Quote=引用 43 楼 yelang 的回复:]
1、我不知道你为什么要开那么多线程,我看到你一共定义了四个线程,开启至少开了三个。
2、连接和发送为什么要放在两个线程里做?

首先我认为,你只需要开一个线程,也就是监听线程就可以了。连接远程主机和发送数据,完全没有必要再多开一个线程出来。你说你要做十个连接,就开十个线程,那你要是连几百台机器,就要开几百个线程出来?那你的内存和CPU能受得了吗?
[/Quote]

先对您的关注表示感谢一下。我做的就是一个转发的,一共2个连接,一个是向上,一个是向下,恩,我是可以考虑把线程数减少一些。
lanserzhao 2011-08-25
  • 打赏
  • 举报
回复
[Quote=引用 44 楼 oonukeoo 的回复:]
1.客户端网络状况差
2.服务器端处理慢 接收缓冲区满
3.包解析问题 注意两端数据、协议格式是否相符
[/Quote]

恩,这几点上我再观注下
萨拉嘿 2011-08-25
  • 打赏
  • 举报
回复
1.客户端网络状况差
2.服务器端处理慢 接收缓冲区满
3.包解析问题 注意两端数据、协议格式是否相符
yelang 2011-08-25
  • 打赏
  • 举报
回复
1、我不知道你为什么要开那么多线程,我看到你一共定义了四个线程,开启至少开了三个。
2、连接和发送为什么要放在两个线程里做?

首先我认为,你只需要开一个线程,也就是监听线程就可以了。连接远程主机和发送数据,完全没有必要再多开一个线程出来。你说你要做十个连接,就开十个线程,那你要是连几百台机器,就要开几百个线程出来?那你的内存和CPU能受得了吗?
auogsy 2011-08-25
  • 打赏
  • 举报
回复
up,up,up
ak476565 2011-08-25
  • 打赏
  • 举报
回复
用UDP多好呀
足球中国 2011-08-24
  • 打赏
  • 举报
回复
楼主应该整个的框框有些问题。
足球中国 2011-08-24
  • 打赏
  • 举报
回复
楼主不防先看一下,开源比较好些的通讯代码。看过别人怎么写再查一下自己写的哪些地方不对。
烈火蜓蜻 2011-08-24
  • 打赏
  • 举报
回复
try
{
do
{
if (!RemoteIsConnected)
{
ConnectToRemote(); //连接远程 服务器
tRemoteSocketRead.Start(); //启动监听线程
if (RemoteIsConnected)
{
tLogin.Start();//如果成功连接后开始发送登录协议
}
}
Thread.Sleep(iConnectTime);
}
while (RemoteIsConnected);// 如果连接上,你还循环,这里不对吧,应该是没有连接上继续循环吧
}
catch { }
}

while (RemoteIsConnected); 改成 while (!RemoteIsConnected);

还有我没有看到你的程序哪里有执行
tConnectToRemote线程句柄,开始执行啊,

也就是没看到
tConnectToRemote.Start()啊
hangang7403 2011-08-24
  • 打赏
  • 举报
回复
dingqi
烈火蜓蜻 2011-08-24
  • 打赏
  • 举报
回复
“完成端口”(IOCP) 是指 一个线程去完成发送与接收 数据吗?

建议你先百度一下.
ajiangfeijun 2011-08-24
  • 打赏
  • 举报
回复
友情帮顶
lanserzhao 2011-08-24
  • 打赏
  • 举报
回复
[Quote=引用 37 楼 carpathia 的回复:]
你这样的设计类似一个转发服务器的功能了,是不能用多线程这样设计的,这样做很难做好线程同步交互,CPU的效率非常低,很容易会产生问题,10个链接就有几十个线程在跑了,这样是不行的,服务器端程序不是这样设计的
你必须使用“完成端口”(IOCP)来设计类似的服务器,只有重构,才可以达到你想要的目的的
[/Quote]


我贴的代码可能太多了,这位大哥你可能没看,我做的就是一个转发的功能。但你讲的有2点不是的

1 “10个链接就有几十个线程在跑了” 登录数据我只是用一个线程在跑,一个线程里一个for循环 判断是否登录,如果全登录设置到一个全局变量RemoteIsLogin 里,线程结束。然后我另一边通过一个线程一个同步read 堵塞读取上级服务器响应数据,如果 返回回来的登录数据有 发送的登录数据包的编号,所以可以知道是哪个登录成功

2 我做的是客户端的连接,不是服务器端程序呢


另外请教一下,“完成端口”(IOCP) 是指 一个线程去完成发送与接收 数据吗?
Carpathia 2011-08-24
  • 打赏
  • 举报
回复
你这样的设计类似一个转发服务器的功能了,是不能用多线程这样设计的,这样做很难做好线程同步交互,CPU的效率非常低,很容易会产生问题,10个链接就有几十个线程在跑了,这样是不行的,服务器端程序不是这样设计的
你必须使用“完成端口”(IOCP)来设计类似的服务器,只有重构,才可以达到你想要的目的的
加载更多回复(33)

110,499

社区成员

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

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

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