public bool btnstatu = true; //开始停止服务按钮状态
public Thread myThread; //声明一个线程实例
//开始停止服务按钮
private void startService_Click(object sender, EventArgs e)
{
if (btnstatu)
{
// 实例化新线程
myThread = new Thread(new ThreadStart(Listen));
btnstatu = false;
}
else
{
try
{
newsock.Shutdown(SocketShutdown.Both);
}
catch { }
newsock.Close();
myThread.Abort();
btnstatu = true;
}
GC.Collect();//即使垃圾回收
GC.WaitForPendingFinalizers();
}
//监听函数
public void Listen()
{
//后台线程
Thread.CurrentThread.IsBackground = true;
//初始化SOCKET实例
newsock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//初始化终结点实例
ipa = IPAddress.Any; //IPAddress.Parse(textBox1.Text.Trim());
setPort = int.Parse(serverport.Text.Trim());
localEP=new IPEndPoint(ipa,setPort);
try
{
newsock.IOControl(IOControlCode.KeepAliveValues, GetKeepAliveSetting(1,1000,1000), null);
//绑定
newsock.Bind(localEP);
//监听
newsock.Listen(500);
//开始接受连接,异步。
while (true)
{
AcceptDone.Reset();
try
{
newsock.BeginAccept(new AsyncCallback(AcceptCallback), newsock);
}
catch
{
Thread.Sleep(1000);
newsock.BeginAccept(new AsyncCallback(AcceptCallback), newsock);
}
AcceptDone.WaitOne();
}
}
catch (Exception ex)
{
showClientMsg(ex.Message);
}
}
public void AcceptCallback(IAsyncResult ar) //accpet的回调处理函数
{
AcceptDone.Set();
server1 = (Socket)ar.AsyncState;
//将接收到的Socket传给Client,然后继续监听
Client = server1.EndAccept(ar);
Control.CheckForIllegalCrossThreadCalls = false;
DateTimeOffset now = DateTimeOffset.Now;
//将提示信息发送给客户端,并在服务端显示连接信息。
ClientIP = (Client.RemoteEndPoint as IPEndPoint).Address;//获取远程端口的ip地址
ClientPORT = (Client.RemoteEndPoint as IPEndPoint).Port;//获取远程的端口
ClientName = "IP:" + ClientIP + "Port:" + ClientPORT;
StateObject state = new StateObject();
state.workSocket = Client;
state.socketid = ClientName;
try
{
Client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
catch (SocketException)
{
Client.Shutdown(SocketShutdown.Both);
Client.Close();
}
}
public void ReadCallback(IAsyncResult ar)
{
try
{
String content = String.Empty;
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
int bytesRead = handler.EndReceive(ar);
;
if (bytesRead == 0)
{
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
if (bytesRead > 0)
{
string stringdata = ""; //接收到的数据
stringdata += Encoding.GetEncoding("utf-8").GetString(state.buffer, 0, bytesRead);
//显示客户端发送过来的信息
showClientMsg("【" + state.socketid + "】发送消息" + stringdata + "时间:" + DateTime.Now.ToString() + "\r\n");
}
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
catch
{
}
}
问题是点击关闭服务按钮,即btnstatu = false时,就提示
该如何关闭异步产生的socket
------解决思路----------------------
1、设置布尔变量(isListening),用来标识是否正在监听,只有isListening为tru时,在异步接收
2、窗体关闭前,释放监听(isListening置为false,socket对象进行close、赋null值)
------解决思路----------------------
关闭连接必然会报错的,这就是正常流程,关闭的时候只要 Shutdown 就行, 捕获错误后再 Close
另外楼主的监听部分, 使用了异步 BeginAccept, 却又用了AcceptDone来同步, 不是多此一举吗.
接收数据的部分收过一次就关闭连接了, 有可能数据没有一次性全部传过来, 需要考虑多次接收, 楼主的代码是有隐患的.
------解决思路----------------------
如你是想在主线程中关闭子线程的Socket,建议先判断一个子线程是否已经运行完成。如果完成了再去释放子线程中的资源。
但如果子线程是一直在运行了,那你只能做一个开关量来关闭子线程后在释放资源。就像backgroundworker.workerSupportsCancellation一样。。。
------解决思路----------------------
关闭连接倒是不一定报错。
监听部分的确是‘多此一举’。
以下是一个如何‘开始/停止’监听的示例,示例用了TcpListener,自己换成Socket也可以,原理是相同的。
建议新建一个WinForm项目,然后拷贝以下代码,并编译运行,按'Start'按钮开始侦听。
测试客户可以用浏览器,在地址栏输入http://localhost:5678即可。
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
FlowLayoutPanel layoutPanel = new FlowLayoutPanel() { Dock = DockStyle.Fill };
layoutPanel.Controls.AddRange(new Control[] { textBoxPort, buttonStartStop, listBoxLog});
buttonStartStop.Click += button1_Click;
this.Controls.Add(layoutPanel);
}
void button1_Click(object sender, EventArgs e)
{
listening = !listening;
if (listening)
{
int port = int.Parse(textBoxPort.Text);
listenerThread = new Thread(ListenerThread) { IsBackground = true };
listenerThread.Start(port);
}
else
{
listenerThread.Join();
}
buttonStartStop.Text = listening ? "Stop" : "Start";
}
void ListenerThread(object state)
{
try
{
TcpListener listener = new TcpListener(IPAddress.Any, (int)state);
listener.Start();
Log("Listener started on " + state);
while (listening)
{
if (listener.Server.Poll(100, SelectMode.SelectRead)) // 一次最多阻塞100毫秒,以便检查listening标志。
{
Socket socket = listener.AcceptSocket();
Log("Client connected - " + socket.RemoteEndPoint);
StateObject so = new StateObject() {socket = socket };
socket.BeginReceive(so.buffer, 0, so.buffer.Length, SocketFlags.None, OnReceived, so);
}
}
listener.Stop();
Log("Listener stopped");
}
catch (Exception ex)
{
Log("Exception in ListenerThread: " + ex.Message);
}
}
void OnReceived(IAsyncResult iar)
{
try
{
StateObject so = (StateObject)iar.AsyncState;
int received = so.socket.EndReceive(iar);
if (received > 0)
{
string msg = Encoding.UTF8.GetString(so.buffer, 0, received);
so.socket.Send(Encoding.UTF8.GetBytes(DateTime.Now.ToString("s")));
Log(so.socket.RemoteEndPoint + " -> " + msg);
}
Log("Closing connection with " + so.socket.RemoteEndPoint);
so.socket.Shutdown(SocketShutdown.Both);
so.socket.Close();
}
catch (Exception ex)
{
Log("Exception in OnReceived: " + ex.Message);
}
}
void Log(string line)
{
if (this.InvokeRequired)
{
this.BeginInvoke((Action)delegate { Log(line); });
return;
}
listBoxLog.Items.Add(string.Format("[{0:s}] {1}", DateTime.Now, line));
}
TextBox textBoxPort = new TextBox() { Text = "5678" };
Button buttonStartStop = new Button() { Text = "Start" };
ListBox listBoxLog = new ListBox() { Size = new Size(400, 300) };
Thread listenerThread;
bool listening = false;
private class StateObject
{
public Socket socket;
public byte[] buffer = new byte[4 * 1024];
}
}
------解决思路----------------------
你可以把 listenerThread.Join()
理解为
while( listenerThread.IsAlive)
{
sleep(1);
}
当然内部实现不会这么低级就是了,但是作用是一样的,当然用sleep来阻塞当前线程效率就低的多了
------解决思路----------------------
关闭的时候同时关闭
private void ClearClient()
{
if (AcceptSockAsyn != null)
{
AcceptSockAsyn.Dispose();
AcceptSockAsyn = null;
}
EndPoint[] ep = new EndPoint[connectClient.Keys.Count];
connectClient.Keys.CopyTo(ep, 0);
Token token;
SocketAsyncEventArgs args;
for (int i = 0; i < ep.Length; ++i)
{
args = connectClient[ep[i]];
token = args.UserToken as Token;
CloseClientSocket(token);
}
connectClient.Clear();
ep = null;
}