小弟想做一个简单的异步socket模型。也参考了网上的代码,可一开始就出问题了。封装了一个服务器端类,类中包含服务器端监听套接字,具体代码如下:
class CMiniTcpSvr
{
private IPAddress m_LocalIP;
private Socket _svrSock;
private ushort _port;
private static ManualResetEvent myReset = new ManualResetEvent(false);
Thread m_ListenThread;//负责接受连接的线程
public CMiniTcpSvr(ushort SvrPort)
{
_port = SvrPort;
m_ListenThread = null;
//得到服务器本机地址
IPHostEntry myhost = new IPHostEntry();
myhost = Dns.GetHostByName(""); String IPString = myhost.AddressList[0].ToString(); m_LocalIP=IPAddress.Parse(IPString);
}
/// <summary>
/// 监听线程,负责接受客户端的连接请求
/// </summary>
private void ListenThread()
{
while (true)
{
myReset.Reset();
_svrSock.BeginAccept(new AsyncCallback(AcceptConn), _svrSock);
myReset.WaitOne();
}
}
public void Start()
{
try
{
//初始化socket
_svrSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//绑定端口
IPEndPoint iep = new IPEndPoint(m_LocalIP, _port);
_svrSock.Bind(iep);
//开始监听
_svrSock.Listen(100);
//开启线程接收连接请求
m_ListenThread = new Thread(new ThreadStart(ListenThread));
m_ListenThread.Start();
}
catch (Exception error)
{
throw (new ApplicationException(error.Message));
}
}
///<summary>
///客户端连接处理函数
///</summary>
///<paramname="iar">欲建立服务器连接的Socket对象</param>
protected virtual void AcceptConn(IAsyncResult iar)
{
myReset.Set();
//接受一个客户端的连接请求
Socket oldserver = (Socket)iar.AsyncState;
if (oldserver == null) return;
Socket client = oldserver.EndAccept(iar);
//继续接受客户端
//_svrSock.BeginAccept(new AsyncCallback(AcceptConn), _svrSock);
}
public void Stop()
{
try
{
if (_svrSock.Connected)
{
_svrSock.Shutdown(SocketShutdown.Both);
}
m_ListenThread.Abort();
m_ListenThread = null;
_svrSock.Close();
_svrSock = null;
}
catch (Exception error)
{
throw (new ApplicationException(error.Message));
}
}
}
在外部窗口中调用Start没有出现异常而且检查发现的确是在指定端口上监听了,可当在窗口上调用Stop想关闭服务器的时候出现异常,提示错误代码为:Socket client = oldserver.EndAccept(iar);说对象已经被释放了。
我一开始觉得奇怪,因为我还没做客户端连接呢,只是在服务器端做开始和关闭的动作,怎么就跑到AcceptConn这个函数里面去了呢,这个回调函数不是应该在有客户端连接请求的时候才被调用的么??怎么在执行Stop函数里面的 _svrSock.Close();
即套接字关闭的时候会跑到连接回调函数AcceptConn中去呢???小弟真是郁闷无比,现在问题的焦点就在于:当执行Stop函数的时候怎么会去执行那个连接回调函数的呢????
请各位帮帮忙看看呢!!!
class CMiniTcpSvr
{
private IPAddress m_LocalIP;
private Socket _svrSock;
private ushort _port;
private static ManualResetEvent myReset = new ManualResetEvent(false);
Thread m_ListenThread;//负责接受连接的线程
public CMiniTcpSvr(ushort SvrPort)
{
_port = SvrPort;
m_ListenThread = null;
//得到服务器本机地址
IPHostEntry myhost = new IPHostEntry();
myhost = Dns.GetHostByName(""); String IPString = myhost.AddressList[0].ToString(); m_LocalIP=IPAddress.Parse(IPString);
}
/// <summary>
/// 监听线程,负责接受客户端的连接请求
/// </summary>
private void ListenThread()
{
while (true)
{
myReset.Reset();
_svrSock.BeginAccept(new AsyncCallback(AcceptConn), _svrSock);
myReset.WaitOne();
}
}
public void Start()
{
try
{
//初始化socket
_svrSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//绑定端口
IPEndPoint iep = new IPEndPoint(m_LocalIP, _port);
_svrSock.Bind(iep);
//开始监听
_svrSock.Listen(100);
//开启线程接收连接请求
m_ListenThread = new Thread(new ThreadStart(ListenThread));
m_ListenThread.Start();
}
catch (Exception error)
{
throw (new ApplicationException(error.Message));
}
}
///<summary>
///客户端连接处理函数
///</summary>
///<paramname="iar">欲建立服务器连接的Socket对象</param>
protected virtual void AcceptConn(IAsyncResult iar)
{
myReset.Set();
//接受一个客户端的连接请求
Socket oldserver = (Socket)iar.AsyncState;
if (oldserver == null) return;
Socket client = oldserver.EndAccept(iar);
//继续接受客户端
//_svrSock.BeginAccept(new AsyncCallback(AcceptConn), _svrSock);
}
public void Stop()
{
try
{
if (_svrSock.Connected)
{
_svrSock.Shutdown(SocketShutdown.Both);
}
m_ListenThread.Abort();
m_ListenThread = null;
_svrSock.Close();
_svrSock = null;
}
catch (Exception error)
{
throw (new ApplicationException(error.Message));
}
}
}
在外部窗口中调用Start没有出现异常而且检查发现的确是在指定端口上监听了,可当在窗口上调用Stop想关闭服务器的时候出现异常,提示错误代码为:Socket client = oldserver.EndAccept(iar);说对象已经被释放了。
我一开始觉得奇怪,因为我还没做客户端连接呢,只是在服务器端做开始和关闭的动作,怎么就跑到AcceptConn这个函数里面去了呢,这个回调函数不是应该在有客户端连接请求的时候才被调用的么??怎么在执行Stop函数里面的 _svrSock.Close();
即套接字关闭的时候会跑到连接回调函数AcceptConn中去呢???小弟真是郁闷无比,现在问题的焦点就在于:当执行Stop函数的时候怎么会去执行那个连接回调函数的呢????
请各位帮帮忙看看呢!!!
解决方案 »
- cms系统问题
- 关于console控制台程序的main函数参数问题。
- 求个 串口通信技术
- 请教一种算法, 实现数据存储和计算
- winform combox 自动检索的问题?
- 请问这个结构的返回字节数为什么是16啊?
- 求一条分类模糊查询的SQL语句以及文本框内容模糊匹配数据库字段并显示问题,在线,急等...........................
- DataGridView 中批量删除写入数据库的语句(access)是怎样写的?
- 在c#如何将DataGridview中的内容打印出来?
- Nlog 如何用BufferingTargetWrapper
- 想用winform程序控制一个windows服务 该如何做?
- this关键字
_svrSock.Shutdown(SocketShutdown.Both);
但是后台线程还在监听,你调整一下顺序看看?
public void Stop()
{
try
{
if (_svrSock.Connected)
{
_svrSock.Shutdown(SocketShutdown.Both);
}
//将线程先停掉后,再Shutdown和关闭socket连接看看?
m_ListenThread.Abort();
m_ListenThread = null;
_svrSock.Close();
_svrSock = null;
}
{
_svrSock.Shutdown(SocketShutdown.Both);
}
m_ListenThread.Abort();
m_ListenThread = null;
_svrSock.Close();
_svrSock = null;
感觉这里的顺序有问题 ,因为当你调用 m_ListenThread.Abort()这个方法的时候,抛出异常,然而后面的代码就不会动行了。你去看一下msdn里面Thread.Abort()这个方法。每次调用都会抛出异常,最好你放到最后面,也可以不用加。当代码运行完时这个线程会自动关闭,前提不要有循环。
我一直不太会用.shutdown
现在才知道shutdownboth是关闭了listen 的那个socket和accpet()返回的那个socket
是吧?
我刚刚试过了,先关闭线程再关闭套接字问题依然存在!
3楼的兄弟:
监听线程里的确是有一个循环在的,而且我不希望在关闭监听服务器的时候也必须同时就关闭窗口,故需要用到abort来停止线程的。
现在我觉得头大的地方在于:_svrSock.BeginAccept(new AsyncCallback(AcceptConn), _svrSock);这注册了接受连接的回调函数,不是应该当有连接请求的时候系统才会自动的调用AcceptConn函数的么,我想确定的就是:是不是真的是在系统有连接请求的时候才会自动调用该函数,如果是的话那不是就很奇怪了么,为什么在运行stop的时候还会调用到AcceptConn函数呢???