VB.NET C/S结构的网络通信问题

wangfeng12345678 2011-07-21 04:49:05
下面的程序是网上搜的,可以正常运行.但我有下面两个问题,请高手指教.
1,客户端程序退出后,再次运行,无法再次连接到服务器(因为服务器已停止了侦听,我知道原因,但我不知道怎么改程序),请问如何对程序进行修改,可以实现再次连接.也就是说服务器只要开启了侦听后,客户端可以任意断开或连接.
2.客户端可以向服务器端发送数据.那么服务器端怎么向客户端发送数据呢?



'================================以下是服务器端程序=============================
Imports System.Net.Sockets

'使用到TcpListen类

Imports System.Threading

'使用到线程

Imports System.IO

'使用到StreamReader类


Public Class Form1
Private iPort As Integer = 8000

Private thThreadRead As Thread

'创建线程,用以侦听端口号,接收信息

Private tlTcpListen As TcpListener

'侦听端口号

Private blistener As Boolean = True

'设定标示位,判断侦听状态

Private nsStream As NetworkStream

'创建接收的基本数据流

Private srRead As StreamReader

'从网络基础数据流中读取数据

Private tcClient As TcpClient

Private Sub Listen()

Try

tlTcpListen = New TcpListener(iPort)

'以8000端口号来初始化TcpListener实例

tlTcpListen.Start()

'开始监听

StatusBar1.Text = "正在监听..."

tcClient = tlTcpListen.AcceptTcpClient()

'通过TCP连接请求

nsStream = tcClient.GetStream()

'获取用以发送、接收数据的网络基础数据流

srRead = New StreamReader(nsStream)

'以得到的网络基础数据流来初始化StreamReader实例

StatusBar1.Text = "已经建立TCP连接!"

'循环侦听

While blistener

Dim sMessage As String = srRead.ReadLine()

'从网络基础数据流中读取一行数据

If (sMessage = "STOP") Then

tlTcpListen.Stop()

'关闭侦听

nsStream.Close()

srRead.Close()

'释放资源

StatusBar1.Text = "无连接!"

thThreadRead.Abort()

'中止线程

Return

Else

'判断是否为断开TCP连接控制码

Dim sTime As String = DateTime.Now.ToShortTimeString()

'获取接收数据时的时间

ListBox1.Items.Add(sTime + " " + sMessage)

End If

End While

Catch ex As System.Security.SecurityException

MessageBox.Show("侦听失败!", "错误")

End Try

End Sub


Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Control.CheckForIllegalCrossThreadCalls = False
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
thThreadRead = New Thread(New ThreadStart(AddressOf Listen))

'以Listen过程来初始化线程实例

thThreadRead.Start()

'启动线程

Button1.Enabled = False

StatusBar1.Text = "服务已经启动!"

StatusBar1.ForeColor = Color.Red


End Sub


Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)

Try

thThreadRead.Abort() '中止线程

tlTcpListen.Stop() '关闭侦听

tcClient.Close()

nsStream.Close()

srRead.Close() '释放资源

Catch

End Try

If disposing Then

If Not (components Is Nothing) Then

components.Dispose()

End If

End If

MyBase.Dispose(disposing)

End Sub

'Private Sub Speech_control_master_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
' Control.CheckForIllegalCrossThreadCalls = False
'End Sub
End Class

'================================以下是客户端程序=============================

Imports System.Net.Sockets

'使用到TcpListen类

Imports System.IO

'使用到StreamWriter类
'使用IPAddress类、IPHostEntry类等
Imports System.Net

Public Class Form1



Private swWriter As StreamWriter

'用以向网络基础数据流传送数据

Private nsStream As NetworkStream

'创建发送数据的网络基础数据流

Private tcpClient As TcpClient

'通过它实现向远程主机提出TCP连接申请

Private tcpConnect As Boolean = False

'定义标识符,用以表示TCP连接是否建立



Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Control.CheckForIllegalCrossThreadCalls = False

End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim ipRemote As IPAddress

Dim sHostName As String

Dim tcpClient As TcpClient

Try

ipRemote = IPAddress.Parse(TextBox1.Text)

Catch

MessageBox.Show("输入的IP地址不合法!", "错误提示!")

Return

'判断给定的IP地址的合法性

End Try

Try

tcpClient = New TcpClient(TextBox1.Text, 8000)

'对远程主机的8000端口提出TCP连接申请

nsStream = tcpClient.GetStream()

'通过申请,并获取传送数据的网络基础数据流

swWriter = New StreamWriter(nsStream)

'使用获取的网络基础数据流来初始化StreamWriter实例


Button1.Enabled = False

Button2.Enabled = True

tcpConnect = True

StatusBar1.Text = "已经连接!"

Catch

MessageBox.Show("无法和远程主机8000端口建立连接!", "错误提示!")

Return

End Try


End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
If (TextBox2.Text <> "") Then

swWriter.WriteLine(TextBox2.Text)

'刷新当前数据流中的数据

swWriter.Flush()

TextBox2.Text = ""

Else

MessageBox.Show("发送信息不能为空!", "错误提示!")

End If


End Sub

Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)

If tcpConnect Then

swWriter.WriteLine("STOP")

'发送控制码

swWriter.Flush()

'刷新当前数据流中的数据

nsStream.Close()

swWriter.Close()

'清除资源 ( )

End If

If disposing Then

If Not (components Is Nothing) Then

components.Dispose()

End If

End If

MyBase.Dispose(disposing)

End Sub



End Class







...全文
339 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
looier 2011-08-01
  • 打赏
  • 举报
回复
感谢,共同努力学习哈
ycproc 2011-07-25
  • 打赏
  • 举报
回复
如果是你自己去判断额话 是不可能的

我要关闭QQ 不会给腾讯提前通知的

你可以自己做心跳包 去主动和 在线的去保持长连接 这样试试看
woowtaotao 2011-07-25
  • 打赏
  • 举报
回复
顶下下下
沐NeMo 2011-07-22
  • 打赏
  • 举报
回复
   Private Sub ClientStart()
'创建IPEndPoint实例
Dim ipep As New IPEndPoint(IPAddress.Any, ClientPort)
'创建一个套接字,将所创建的套接字与IPEndPoint绑定
clientSocket = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
clientSocket.Bind(ipep)
'设置套接字为收听模式
clientSocket.Listen(10)
While ListenFlag
Try
'在套接字上接收接入的连接
AcceptSocket = clientSocket.Accept()
clientThread = New Thread(New ThreadStart(AddressOf ReceiveData))
clientThread.IsBackground = True
clientThread.Start()
Catch ex As Exception
ShowMsg("监听出错:" & ex.Message)
End Try
End While
End Sub

Private Sub ReceiveData()
Dim ShowReciveMsgDel As New ShowReciveMsg(AddressOf ShowReciveMsgFun)
While True
Dim bufLen As Integer = 0
Dim dataRv As Byte() = New Byte(1023) {}
Try
bufLen = AcceptSocket.Available
AcceptSocket.Receive(dataRv, 0, bufLen, SocketFlags.None)
If bufLen = 0 Then
Continue While
End If
Catch ex As Exception
ShowMsg("在接受数据过程中:" & ex.Message)
Exit Sub
End Try
Dim RevMsgString As String = Encoding.Unicode.GetString(dataRv).Substring(0, bufLen)
If RevMsgString.StartsWith("cmd") Then
'处理的是服务器命令:
DoCmd(RevMsgString)
End If
Me.RichTextBoxMsg.Invoke(ShowReciveMsgDel, "服务端信息:" & vbCr & RevMsgString)
End While
End Sub

Private Sub DoCmd(ByVal CmdStr As String)
'...
End Sub
沐NeMo 2011-07-22
  • 打赏
  • 举报
回复
其实你这个程序是最简单的例子,不可以用到你想要的程序里面的。
收发信息,互发信息,前面程序的逻辑要改一改吧。
我有做过类似的。还有这个。服务端和客服端在不同的机器上,可以互发信息的。



服务端关键代码:
 Private Sub Listener()
If uClient IsNot Nothing Then
uClient.Close()
End If
Dim msg As String
uClient = New UdpClient(port)
Dim mi As MethodInvoker = New MethodInvoker(AddressOf ShowRecMsg)
While True
If uClient.Available > 0 Then
msg = ""
Dim recdata As Byte() = uClient.Receive(RemoteIpEndPoint)
msg = System.Text.Encoding.Unicode.GetString(recdata)
If msg.StartsWith("cmd|") Then
DoCmd(msg, RemoteIpEndPoint.Address.ToString)
End If
RecMsg = String.Format("{0}:{1}{2}", RemoteIpEndPoint.Address.ToString, vbCrLf, msg)
Me.BeginInvoke(mi)
'让主线程去访问自己创建的控件.这里采用全局变量:RecMsg
End If
End While
End Sub


客服端关键代码:
 Private Sub Listener()
If uClient IsNot Nothing Then
uClient.Close()
End If
Dim msg As String
uClient = New UdpClient(port)
Dim mi As MethodInvoker = New MethodInvoker(AddressOf ShowRecMsg)
While True
If uClient.Available > 0 Then
Try
msg = ""
Dim recdata As Byte() = uClient.Receive(RemoteIpEndPoint)
msg = System.Text.Encoding.Unicode.GetString(recdata)
If msg.StartsWith("cmd|") Then
DoCmd(msg)
End If
RecMsg = String.Format("{0}:{1}{2}", RemoteIpEndPoint.Address.ToString, vbCrLf, msg)
BeginInvoke(mi)
'让主线程去访问自己创建的控件.这里采用全局变量:RecMsg
Catch ex As Exception

End Try
End If
End While
End Sub

沐NeMo 2011-07-22
  • 打赏
  • 举报
回复
是因为你的:
' ....
Else
Dim sTime As String = DateTime.Now.ToShortTimeString()
'获取接收数据时的时间
ListBox1.Items.Add(sTime + " " + sMessage)
沐NeMo 2011-07-22
  • 打赏
  • 举报
回复
呵呵。我也遇到过的见图:

---
应该可以设置。接收数据时候检查是否连接,连接状态。
我懒得去找源代码了。源代码也没有在我这个电脑上。
沐NeMo 2011-07-22
  • 打赏
  • 举报
回复
找了代码。
退出客服端时候,你关闭Socket要等待发送的数据流已经完全发送过去后才关闭吧。

参考http://msdn.microsoft.com/zh-cn/library/bc68k4td(v=vs.80).aspx

Close 方法可关闭远程主机连接,并释放所有与 Socket 关联的托管资源和非托管资源。关闭后,Connected 属性将设置为 false。

对于面向连接的协议,建议先调用 Shutdown,然后再调用 Close。这可以确保在已连接的套接字关闭之前,已发送和接收该套接字上的所有数据。

如果需要在不首先调用 Shutdown 的情况下调用 Close,则可以将 DontLinger 选项设置为 false,并且指定一个非零的超时间隔,从而可以确保排队等待输出的数据得到发送。这样,Close 将会一直阻止到发送完该数据或指定的时限超时为止。如果将 DontLinger 设置为 false,并且指定了一个非零的超时间隔,Close 将会释放连接并自动放弃排队等待输出的数据。
 
'
Socket.Close(10)
'等一秒
Thread.Sleep(1000)
'退出程序
Application.Exit()
wangfeng12345678 2011-07-22
  • 打赏
  • 举报
回复
高手再次赐教:
我在网上找了个很简单的源程序,可实现客户端和服务器端互相发送消息。但每次只要客户端断开连接或关闭,服务器端和客户端就会同时出错。请问出错的原因是什么?出错代码和出错信息如下:

服务器端出错代码为:
Private Sub ReceiveData(ByVal pIAsyncResult As IAsyncResult)
Dim intByte As Int16
'回调函数结束后,重新建立线程,继续接收数据,该如何结束线程???利用定时器定时处理接收到的数据...
Dim myAsyncCallBack As New AsyncCallback(AddressOf ReceiveData)
intByte = EndSocket.EndReceive(pIAsyncResult)
txt_ip_receive.Text += Encoding.ASCII.GetString(bteAcceptData) + vbCrLf
EndSocket.BeginReceive(bteAcceptData, 0, 1024, 0, myAsyncCallBack, EndSocket)
End Sub

intByte = EndSocket.EndReceive(pIAsyncResult)这句就是出错的地方。出错信息是:无法访问已释放的对象。 对象名:“System.Net.Sockets.Socket”。

客户端出错代码为:
Private Sub ReceiveData(ByVal pIAsyncResult As IAsyncResult)
Dim intByte As Int16
'回调函数结束后,重新建立线程,继续接收数据,该如何结束线程???利用定时器定时处理接收到的数据...
Dim myAsyncCallBack As New AsyncCallback(AddressOf ReceiveData)
intByte = mySocket.EndReceive(pIAsyncResult)
txt_Receive_data.Text += Encoding.ASCII.GetString(bteAcceptData)
mySocket.BeginReceive(bteAcceptData, 0, 1024, 0, myAsyncCallBack, mySocket)

End Sub

intByte = mySocket.EndReceive(pIAsyncResult)这句就是出错的地方。出错信息是:远程主机强迫关闭了一个现有的连接。
沐NeMo 2011-07-22
  • 打赏
  • 举报
回复
我知道的,互发信息,应该要用到SOCKET类。还有其他的我就暂时没有去了解吧。
不过.net已经帮我们封装好简洁,简单的:
TcpClient
UdpClient
这两个类也是属于SOCKET类。我们可以直接使用。而且对于简单的程序也够用了。
你在1楼就有用到TcpClient而我在6楼就有用到UdpClient。
更多功能更复杂的,可以要使用Socket类了。
--
另外:TcpClient,UdpClient一两百太电脑应该没问题。看发送的信息量吧。或者直接用这个Socket类就得了。
wangfeng12345678 2011-07-22
  • 打赏
  • 举报
回复
非常感谢楼上的高手的指点!!!楼上的程序太强悍了,只是这个程序对我来说还是太复杂,一时半会研究不透。其实我只是想要一个最简单的客户端和服务器能够互相发送接收消息的功能。
以前用的VB6,里面有WINSOCK控件,现在用VB.NET网络编程不习惯。所以想问下:如果要实现互发消息的功能,必须使用SOCKET类吗?有没有入门级的教程或书本可以推荐下?

还有我想询问下,如果客户端的数量增加,比如,有一两百台电脑,服务器端会不会出现什么问题?
wangfeng12345678 2011-07-22
  • 打赏
  • 举报
回复
我用
Try
出错的语句
Catch ex As Exception
exit sub
End Try
把出错的语句给忽略掉了。现在程序看起来运行正常了,也没出错了。不知道这样行不行?客户端多了之后会不会出问题。
music_0000 2011-07-22
  • 打赏
  • 举报
回复
http://download.csdn.net/source/2874845
wangfeng12345678 2011-07-21
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 linjimu 的回复:]
1:你关闭客服端时候,会执行:
'--下面的意思是关闭服务端,停止侦听。
swWriter.WriteLine("STOP")
'发送控制码
swWriter.Flush()
'停止服务功能。
你把这两句去掉就可以了。

2:你要在服务端设置接收客服端信息,接收到会有一个与客服端对话的Sockets。
利益这个Sockets,就可以给客服端发送数据。
[/Quote]
再次请教高手,我把swWriter.WriteLine("STOP")和swWriter.Flush()这两句去掉了,可是客户端程序一退出,服务器端就会不但的接收到空的数据.这是什么原因啊?
服务器窗口中接收的数据如下(前三行数据是程序运行是发送的,后面的空的数据都是客户端关闭后,服务器上接收到的,而且不断的接收,停不下来):

23:01 aaa
23:01 bbb
23:01 ccc
23:01
23:01
23:01
23:01
23:01
23:01
23:01
23:01
23:01
……
沐NeMo 2011-07-21
  • 打赏
  • 举报
回复
1:你关闭客服端时候,会执行:
'--下面的意思是关闭服务端,停止侦听。
swWriter.WriteLine("STOP")
'发送控制码
swWriter.Flush()
'停止服务功能。
你把这两句去掉就可以了。

2:你要在服务端设置接收客服端信息,接收到会有一个与客服端对话的Sockets。
利益这个Sockets,就可以给客服端发送数据。
rmini 2011-07-21
  • 打赏
  • 举报
回复
不懂,等待高人,继续关注

16,553

社区成员

发帖
与我相关
我的任务
社区描述
VB技术相关讨论,主要为经典vb,即VB6.0
社区管理员
  • VB.NET
  • 水哥阿乐
  • 无·法
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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