主程序需要动态加载一个dll,该dl初始化时启动了一个UdpClient,主程序退出时【长】……

wzuomin 2008-04-18 04:45:41
主程序需要动态加载一个dll,该dl初始化时启动了一个UdpClient,打开并监视一个端口
在主程序关闭退出后,再启动的话会提示错误: 通常每个套接字地址 (协议/网络地址/端口) 只允许使用一次
分析造成这个问题的原因是:主程序退出时动态加载的dll没有释放该端口

这个问题该怎么解决啊?
...全文
218 24 打赏 收藏 转发到动态 举报
写回复
用AI写文章
24 条回复
切换为时间正序
请发表友善的回复…
发表回复
天明啊 2011-03-24
  • 打赏
  • 举报
回复
wzuomin 2008-05-06
  • 打赏
  • 举报
回复
这个问题真是头疼啊!没有好的解决方法吗?
谢谢大家,但是仍没有完美的解决呐!
q979851 2008-05-06
  • 打赏
  • 举报
回复
有时候程序窗体关了,但任务栏上的进程没关,
所以造成端口没关,
感觉winform没点不稳定
fox1999 2008-04-21
  • 打赏
  • 举报
回复
UDP 有時會這樣,你打開一個端口,關閉後,馬上再打開,會提示端口已被占用
wzuomin 2008-04-20
  • 打赏
  • 举报
回复
希望有人继续关注!
wzuomin 2008-04-19
  • 打赏
  • 举报
回复
自动转换的C#代码如下:不能保证能正常运行,呵呵
主程序代码:

using System.Reflection;

public class Form1
{

private System.Windows.Forms.ToolStrip TestToolStrip;

private void Form1_Load(object sender, System.EventArgs e)
{
this.TestToolStrip = new ToolStrip();
this.TestToolStrip.Items.Add(new ToolStripButton("TestButton"));
this.TestToolStrip.Items.Add(new ToolStripComboBox("TestComboBox"));
this.TestToolStrip.Items.Add(new ToolStripDropDownButton("TestDropDownButton"));
this.TestToolStrip.Dock = DockStyle.Top;
this.Controls.Add(this.TestToolStrip);

string Path = Application.StartupPath + "\\Extended";
string FileName = FileSystem.Dir(Path + "\\*.dll");

while (FileName != "") {
AddExtendItem(Path + "\\" + FileName);
FileName = FileSystem.Dir();
}
}

private void AddExtendItem(string dllFilePath)
{
try {
Assembly a = Assembly.LoadFrom(dllFilePath);
Type[] MyTypes = a.GetTypes();

foreach (Type t in MyTypes) {
if (t.Name == "ExtendedItem") {
object[] Parameters = {this.TestToolStrip};
object obj = Activator.CreateInstance(t, Parameters);
break; // TODO: might not be correct. Was : Exit For
}
}
}
catch (Exception ex) {
Interaction.MsgBox(ex.Message, MsgBoxStyle.Critical, "Error");
}
}

}


测试用的dll代码如下:

using System.Windows.Forms;

public class ExtendedItem
{

ToolStripDropDownButton Testbtn;
private Threading.Thread ListenThread;
private Net.Sockets.UdpClient listen;

public ExtendedItem(ToolStrip _ToolStrip)
{
this.Testbtn = new ToolStripDropDownButton("TestDllDropDownButton");
{
this.Testbtn.DropDownItems.Add("TestItem1");
this.Testbtn.DropDownItems.Add("TestItem2");
this.Testbtn.DropDownItems.Add("CloseUdpClient", null, Close);
}
_ToolStrip.Items.Add(this.Testbtn);

try {
listen = new Net.Sockets.UdpClient(2525);
ListenThread = new Threading.Thread(ListenPort);
ListenThread.Start();
}
catch (Exception ex) {
Interaction.MsgBox(ex.Message, MsgBoxStyle.Critical, "Error");
}
}

//侦听指定端口的广播地址UDP包
private void ListenPort()
{
Net.IPEndPoint tempEnd = new Net.IPEndPoint(Net.IPAddress.Any, 2525);
while (true) {
Application.DoEvents();
try {
byte[] recb = listen.Receive(tempEnd);
CheckMessage(recb);
}
catch (Exception e) {
break; // TODO: might not be correct. Was : Exit Try
}
}
}

private void CheckMessage(byte[] bytes)
{
//省略
}

private void Close(object sender, System.EventArgs e)
{
if (ListenThread != null)
ListenThread.Abort();
if (listen != null)
listen.Close();
}

}
wzuomin 2008-04-19
  • 打赏
  • 举报
回复
举个例子说明一下吧
比如我有个主程序,在Load的时候会在某个指定目录中查找是否有dll需要加载
代码如下:

Imports System.Reflection

Public Class Form1

Private TestToolStrip As System.Windows.Forms.ToolStrip

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Me.TestToolStrip = New ToolStrip
Me.TestToolStrip.Items.Add(New ToolStripButton("TestButton"))
Me.TestToolStrip.Items.Add(New ToolStripComboBox("TestComboBox"))
Me.TestToolStrip.Items.Add(New ToolStripDropDownButton("TestDropDownButton"))
Me.TestToolStrip.Dock = DockStyle.Top
Me.Controls.Add(Me.TestToolStrip)

Dim Path As String = Application.StartupPath + "\Extended"
Dim FileName As String = Dir(Path + "\*.dll")

While FileName <> ""
Call AddExtendItem(Path + "\" + FileName)
FileName = Dir()
End While
End Sub

Private Sub AddExtendItem(ByVal dllFilePath As String)
Try
Dim a As [Assembly] = [Assembly].LoadFrom(dllFilePath)
Dim MyTypes As Type() = a.GetTypes()

For Each t As Type In MyTypes
If t.Name = "ExtendedItem" Then
Dim Parameters() As Object = {Me.TestToolStrip}
Dim obj As [Object] = Activator.CreateInstance(t, Parameters)
Exit For
End If
Next
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.Critical, "Error")
End Try
End Sub

End Class



我编写了一个测试用的dll,代码如下:

Imports System.Windows.Forms

Public Class ExtendedItem

Dim Testbtn As ToolStripDropDownButton
Private ListenThread As Threading.Thread
Private listen As Net.Sockets.UdpClient

Public Sub New(ByVal _ToolStrip As ToolStrip)
Me.Testbtn = New ToolStripDropDownButton("TestDllDropDownButton")
With Me.Testbtn.DropDownItems
.Add("TestItem1")
.Add("TestItem2")
.Add("CloseUdpClient", Nothing, AddressOf Close)
End With
_ToolStrip.Items.Add(Me.Testbtn)

Try
listen = New Net.Sockets.UdpClient(2525)
ListenThread = New Threading.Thread(AddressOf ListenPort)
ListenThread.Start()
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.Critical, "Error")
End Try
End Sub

'侦听指定端口的广播地址UDP包
Private Sub ListenPort()
Dim tempEnd As New Net.IPEndPoint(Net.IPAddress.Any, 2525)
While True
Application.DoEvents()
Try
Dim recb As Byte() = listen.Receive(tempEnd)
Call CheckMessage(recb)
Catch e As Exception
Exit Try
End Try
End While
End Sub

Private Sub CheckMessage(ByVal bytes() As Byte)
'省略
End Sub

Private Sub Close(ByVal sender As Object, ByVal e As System.EventArgs)
If ListenThread IsNot Nothing Then ListenThread.Abort()
If listen IsNot Nothing Then listen.Close()
End Sub

End Class



这样,程序运行后,在主程序的 ToolStrip 中会增加一个DropDownButton(该Button带有数个下拉菜单项)。
如果先执行这个button的下拉菜单 CloseUdpClient,再关闭主程序,下次启动不会有任何问题。
但是如果直接关闭主程序,就不行了,下次启动肯定会报错的。
就是这么个情况,麻烦大家给出出主意吧!呵呵。
一会儿把自动转换的C#代码我也贴过来,帮忙看看吧。先谢谢了!
ycg_893 2008-04-19
  • 打赏
  • 举报
回复
UdpClient与主程不是同一线程,当主程退出后,UdpClient还在占用端口并在进程中,所以可以让主程序退出时,终止UdpClient进程.
minioreo 2008-04-19
  • 打赏
  • 举报
回复
mark
yunfeng007 2008-04-19
  • 打赏
  • 举报
回复
??dll不是自己的,那就自己做个Wrapper类来做包装,然后在此做清理的工作
yunfeng007 2008-04-19
  • 打赏
  • 举报
回复

internal class UdpClient
{
public UdpClient(){}//初始化,构造函数
~UdpClient(){}//显示声明析构函数,在此做清理工作
}

possible_Y 2008-04-19
  • 打赏
  • 举报
回复
那是那个动态dll的问题了,让dll的作者自己去改,让他记得做非托管资源的释放
wzuomin 2008-04-19
  • 打赏
  • 举报
回复
楼上说的确实不错,可是动态加载的dll主程序该如何管理或者调用stop方法呢?
我现在就是苦于没法调用动态加载的dll里的方法啊!
shrinerain 2008-04-19
  • 打赏
  • 举报
回复
你需要显式给DLL设计一个清理函数.

由DLL申请的资源, 需要DLL自己来释放.

对于这个DLL, 你可以设计一个初始化函数, 和一个清理函数.

比如, 你给DLL设计一个Start()函数, 负责申请Socket资源, 还有一个Stop()函数,负责撤销Socket资源.

在你EXE调用中, 显式使用Start()来运行DLL, 并且在程序退出事件时, 调用Stop()来让DLL清理资源.
wzuomin 2008-04-19
  • 打赏
  • 举报
回复
UdpClient 只是在一个dll中运行的呀!是动态加载运行的,怎么终止啊?
wzuomin 2008-04-19
  • 打赏
  • 举报
回复
大家提供的方法不知道你们试过没有?说的方法实际上可行么?

我在vb中的Finalize中增加了调用Close方法,还是不行。

还有18楼说的在FormClosing中关闭,怎么个关闭方法啊?

如果我不是动态加载,在主程序中增加 Private Test As TestDll.ExtendedItem
,然后Form Load的时候 Test = New TestDll.ExtendedItem(Me.TestToolStrip)
这样子的话可以用下面方法解决这个问题
Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
Test.Close(Nothing, Nothing)
End Sub
wanghui0380 2008-04-19
  • 打赏
  • 举报
回复
??不是很复杂的问题啊
socket开启了监听端口,但退出的时候,没有关闭监听端口。问题就是如此啊,没啥思维上的障碍嘛

在FormClosing事件里关闭就可以了

如果是自己的dll,也可以加析构函数嘛

yunfeng007 2008-04-19
  • 打赏
  • 举报
回复

using System.Windows.Forms;

public class ExtendedItem
{
//将dll修改,增加析构函数。不行吗?
~ExtendedItem()
{
Close(null,null);
}

private void Close(object sender, System.EventArgs e)
{
if (ListenThread != null)
ListenThread.Abort();
if (listen != null)
listen.Close();
}
}

主线程关闭,dll肯定被释放了,但因为socket没有主动close,端口依然被占用
wzuomin 2008-04-18
  • 打赏
  • 举报
回复
Application.Exit这句加了也不行。
duping9626 2008-04-18
  • 打赏
  • 举报
回复
主程序退出时
Application.Exit()试试呢
加载更多回复(4)

110,533

社区成员

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

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

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