我很无耻的又来求教了,修改后的异步socket的问题

funxu 2011-08-18 05:27:26
先说正题,上午sp1234吴大侠惊鸿一瞥,我受益匪浅,修改后的socket客户端和服务端单进程测试貌似没啥问题了,后来我加大测试力度,四个进程并发访问,不过问题就来了,错误提示如下,状况是客户端先爆意外,然后服务端就开始频繁意外,最后崩溃了,我开始以为是服务端100连接上限惹的祸,加了一些错误处理后反而觉得画蛇添足了,没办法,还是烦劳各位高人指点
C#新人求回帖~~求指导~求虐~求关注~
客户端
System.Net.Sockets.SocketException (0x80004005): A request to send or receive da
ta was disallowed because the socket is not connected and (when sending on a dat
agram socket using a sendto call) no address was supplied
at System.Net.Sockets.Socket.BeginSend(Byte[] buffer, Int32 offset, Int32 siz
e, SocketFlags socketFlags, AsyncCallback callback, Object state)
at ConsoleApplication1.AsynchronousClient.Send(socketstate client, String dat
a) in D:\funxu\c#\New folder\??socke(?????)\??socketclient\ConsoleApplication1\P
rogram.cs:line 217
at ConsoleApplication1.AsynchronousClient.StartClient() in D:\funxu\c#\New fo
lder\??socke(?????)\??socketclient\ConsoleApplication1\Program.cs:line 62

服务端
System.NullReferenceException: Object reference not set to an instance of an object.
at ConsoleApplication1.AsynchronousSocketListener.ReadCallback(IAsyncResult a
r) in D:\funxu\c#\New folder\??socke(?????)\??socketserver\ConsoleApplication1\P
rogram.cs:line 189
代码如下
客户端
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Net;
namespace ConsoleApplication1
{
public class StateObject
{
public byte[] buffer = new byte[256];
public StringBuilder sb = new StringBuilder();
}
public class socketstate
{
public Socket socket=null;
public bool couldbushutdown = false;
public int source;
public StateObject state;
}
public class AsynchronousClient
{
private const int port = 6600;
private static ManualResetEvent connectDone =new ManualResetEvent(false);
private static String response = String.Empty;
private static void StartClient()
{
try
{
IPAddress ipAddress = IPAddress.Parse("172.25.184.86");
IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);
Socket client = new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp);
socketstate socketclient = new socketstate();
socketclient.socket=client;
socketclient.couldbushutdown = false;
client.BeginConnect(remoteEP,new AsyncCallback(ConnectCallback), socketclient);
connectDone.WaitOne();
Send(socketclient, "This is a test<EOF>");
Receive(socketclient);
Monitor(socketclient);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void ConnectCallback(IAsyncResult ar)
{
socketstate client = (socketstate)ar.AsyncState;
try
{
client.source = System.Environment.TickCount;
client.socket.EndConnect(ar);
Console.WriteLine("Socket connected to {0}",client.socket.RemoteEndPoint.ToString());
connectDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
client.couldbushutdown = true;
}
}
private static void MonitorCallback(socketstate client)
{
try
{
while (true)
{
Thread.Sleep(100);
DateTime d = ((new DateTime(1970, 1, 1, 0, 0, 0, 0)));
int temp = System.Environment.TickCount;
int b = temp - client.source;
if (client.couldbushutdown == true)
{
Console.WriteLine("shut down the socket {0}", client.socket.RemoteEndPoint.ToString());
client.socket.Shutdown(SocketShutdown.Both);
client.socket.Close();
break;
}
else
{
if (b > 50000)
{
Console.WriteLine("shut down the socket {0}", client.socket.RemoteEndPoint.ToString());
client.socket.Shutdown(SocketShutdown.Both);
client.socket.Close();
break;
}

}
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void Monitor(socketstate client)
{
try
{

ThreadStart starter = delegate { MonitorCallback(client); };
new Thread(starter).Start();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void Receive(socketstate client)
{
try
{
client.state = new StateObject();
client.socket.BeginReceive(client.state.buffer, 0,256, 0,new AsyncCallback(ReceiveCallback), client);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
client.couldbushutdown = true;
}
}
private static void ReceiveCallback(IAsyncResult ar)
{
socketstate client = (socketstate)ar.AsyncState;
try
{
if (client.couldbushutdown == true)
{
return;
}
int bytesRead = client.socket.EndReceive(ar);
if (bytesRead > 0)
{
client.state.sb.Append(Encoding.Unicode.GetString(client.state.buffer, 0, bytesRead));
client.socket.BeginReceive(client.state.buffer, 0, 256, 0,new AsyncCallback(ReceiveCallback), client);
Console.WriteLine("has been receive" + client.state.sb.ToString());
if (client.state.sb.ToString().IndexOf("<END>") > -1)
{
client.couldbushutdown = true;
}
}
else
{
if (client.state.sb.Length > 1)
{
response = client.state.sb.ToString();
}
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
client.couldbushutdown = true;
}
Console.WriteLine("end receive Response received : {0}", response);
}
private static void Send(socketstate client, String data)
{
byte[] byteData = Encoding.Unicode.GetBytes(data);
client.socket.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), client);
}

private static void SendCallback(IAsyncResult ar)
{
socketstate client = (socketstate)ar.AsyncState;
try
{
int bytesSent = client.socket.EndSend(ar);
Console.WriteLine("Sent {0} bytes to server.", bytesSent);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
client.couldbushutdown = true;
}
}

static void Main(string[] args)
{
int i = 0;
try
{
for (i = 0; i < 50; i++)
{
Thread.Sleep(500);
Thread clientsockets = new Thread(new ThreadStart(StartClient));
clientsockets.Start();
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
Console.WriteLine("thread has finish at" + i.ToString());
Console.ReadLine();
}
}
}
...全文
165 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
funxu 2011-08-19
  • 打赏
  • 举报
回复
经过刚才的测试确实9L的兄台说的很对,就是那个监视进程释放已经释放的资源导致服务器崩溃了,经过修改
1 将监视进程移出死循环,只启动一次
2 监视中的try语句仅包括客户端释放的部分,这样不会造成监视进程意外崩溃
3 取消客户端中的连接超时断开,客户端和服务端只有双方断开会引发意外
4 将服务端的send和receive加入意外判断,因为监视线程独立于其他两个线程,可能这两个进程正在访问socket,而那个socket已经被监视进程断开了,解决方案确实是不要随便在服务端断开连接
funxu 2011-08-19
  • 打赏
  • 举报
回复
估计问题出现在这里。
建议这个socket死链接的管理你只建一个thread,不要每来一个请求,你都建一个thread,你有多线程的时候必须要考虑到数据的线程同步问题,如果你的服务端报错就是因为这个,你多个线程在检测有没有死链接,thread a发现有个socket a死掉了,他关了,但是在thread a关闭的同时,thread b也发现了这个socket a,thread b也尝试关闭socket a,但是socket a已经被thread a关闭了,没有资源了,所以thread b在关闭的时候就报错了,没有引用实例。
确实这里有问题,当时我以为给列表加一个lock就可以了,另外每个个访问都加一个监视确实是我疏忽了,开始只是想做个线程监视当前访问连接的状态,超时或者意外直接断开,后来想还是给个列表监视所有的线程好一些,但是改完后代码忘记移出来了,受教~受教~
funxu 2011-08-19
  • 打赏
  • 举报
回复
确实这个代码是用原来同步的代码改的,呵呵,发送,接受都有阻塞的,但是在测试中会发现客户端偶尔出现问题,所以去掉了,非常感谢LS的代码,今天就测试下
萨拉嘿 2011-08-19
  • 打赏
  • 举报
回复
//服务器端代码
public static void StartListening()
{
byte[] bytes = new Byte[1024];
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPAddress ipAddress = IPAddress.Any;
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 6600);
Socket listener = new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp);
try
{
listener.Bind(localEndPoint);
listener.Listen(100);

Console.WriteLine("Waiting for a connection...");
listener.BeginAccept(new AsyncCallback(AcceptCallback),listener);//此处负责接受连接
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}

public static void AcceptCallback(IAsyncResult ar)
{

Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
socketstate state = new socketstate();
try
{
state.workstatus = true;
state.workSocket = handler;
state.state = new StateObject();
state.workSocket = handler;
state.connecttime = System.Environment.TickCount;
state.state = new StateObject();
socketlist.Add(state);

MonitorCallback(socketlist); //直接对列表进行修改,不启用新线程做处理,此回调函数中本身就是个新线程,再个函数不要乱起名字。。

handler.BeginReceive(state.state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);

listener.BeginAccept(new AsyncCallback(AcceptCallback),listener);//继续接收连接
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
state.workstatus = false;
}
}

你这代码是不原本同步的代码改的。。。。有点摸不着头脑
KARZHOU 2011-08-18
  • 打赏
  • 举报
回复
最近学习IOCP 帮顶
jy251 2011-08-18
  • 打赏
  • 举报
回复
阻塞这个东西是看具体情况的,用不用取决于你的代码实现要求。我觉得你的阻塞没啥问题。
刚刚看了看你服务器的代码,总觉得问题会不会出现在 MonitorCallback 里面,我猜MonitorCallback你是用来解决长时间链接不发送数据,你就认为是可以断开了把。

估计问题出现在这里。
建议这个socket死链接的管理你只建一个thread,不要每来一个请求,你都建一个thread,你有多线程的时候必须要考虑到数据的线程同步问题,如果你的服务端报错就是因为这个,你多个线程在检测有没有死链接,thread a发现有个socket a死掉了,他关了,但是在thread a关闭的同时,thread b也发现了这个socket a,thread b也尝试关闭socket a,但是socket a已经被thread a关闭了,没有资源了,所以thread b在关闭的时候就报错了,没有引用实例。
funxu 2011-08-18
  • 打赏
  • 举报
回复
非常感谢Ls的回答,明天去试下,因为上午有人说不该用阻塞,所以我把原始代码中关于阻塞的部分都去掉了,另外想测试长连接服务端断开客户端才加入的主动断开的函数,看起来是有些问题,明天再修改吧
jy251 2011-08-18
  • 打赏
  • 举报
回复
求知不可耻,谦虚是好事

学习就要敢于询问,你不问,难道你的问题全靠自己弄?等你弄懂了,时间都浪费;了
jy251 2011-08-18
  • 打赏
  • 举报
回复
你的代码我实在是没兴趣看。。太乱了,不过初看一眼,你这个基本是抄写的msdn上的。
既然这样,我看过你的报错信息了。
我有个人的猜想,我没去试过,结果如何需要你自己看看:
客户端,报错说明服务端关闭了socket,具体为什么有两个原因:1,你的客户端在send或者receive之后让socket的可关闭属性设置为了可关闭,那么服务端socket自然就关闭了,你这个链接就断开了。2,你的服务端的accept的异步写得有问题,这个概率比较小,因为既然是msdn上的,那个例子是好的,而且你应该不需要修改那一段的代码。主要看看第一个可能吧。
服务端,引用问题,这个真需要你自己调试了,看看哪一句报错出来,哪个类的对象变量是个null。

给你个原则,一半情况下,除非特殊业务要求,服务器不要主动中途就关闭socket,因为这样很容易导致你客户端报错。对于服务端receivecallback函数中的endrecevie这个的返回是个int,这个int表示你receive到的数据量,如果是0,一半情况下都是客户端socket close了。
所以如果你要正确的退出一次链接,你应该先关闭客户端socket,然后endreceive中int返回0,你再关闭服务端的socket。
hui_play 2011-08-18
  • 打赏
  • 举报
回复
我的程序也用到了socket啊,同时的链接大概要几百个,都没有问题的。
代码太多,没时间看。
xiaotiange 2011-08-18
  • 打赏
  • 举报
回复
求救不是无耻的,那些视你为"无耻"的人才 真正的 无耻卑微恶心
guoyichao 2011-08-18
  • 打赏
  • 举报
回复
用.net 3.5以上开发的话,可以看看http://msdn.microsoft.com/zh-cn/library/bb968780.aspx
用增强的机制开发异步socket,不建议用2.0老一套来搞异步socket了。
funxu 2011-08-18
  • 打赏
  • 举报
回复
个人感觉自己那个状态监控线程写的很弱,资源释放也不怎么好,而且意外处理也存在各种bug,不过还是那句话
C#新人求回帖~~求指导~求虐~求关注~
不给代码可以给思路,不给思路可以给方向,拜谢中.........
funxu 2011-08-18
  • 打赏
  • 举报
回复
服务端代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.Runtime.InteropServices;
using System.Collections;
namespace ConsoleApplication1
{
public class StateObject
{
public const int BufferSize = 1024;
public byte[] buffer = new byte[BufferSize];
public StringBuilder sb = new StringBuilder();
}
public class socketstate
{
public int connecttime;
public Socket workSocket = null;
public StateObject state;
public bool workstatus=false;
}
public class AsynchronousSocketListener
{
public static ManualResetEvent allDone = new ManualResetEvent(false);
public AsynchronousSocketListener()
{
}
static List<socketstate> socketlist = new List<socketstate>();
public static void StartListening()
{
byte[] bytes = new Byte[1024];
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPAddress ipAddress = IPAddress.Any;
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 6600);
Socket listener = new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp);
try
{
listener.Bind(localEndPoint);
listener.Listen(100);
while (true)
{
allDone.Reset();
Console.WriteLine("Waiting for a connection...");
listener.BeginAccept(new AsyncCallback(AcceptCallback),listener);
Monitor(socketlist);
allDone.WaitOne();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
private static void MonitorCallback(List<socketstate> socketlist)
{
try
{
while (true)
{
Thread.Sleep(100);
lock (socketlist)
{
for (int i = socketlist.Count - 1; i >= 0; i--)
{
socketstate socketstate = socketlist[i];
DateTime d = ((new DateTime(1970, 1, 1, 0, 0, 0, 0)));
int temp = System.Environment.TickCount;
int b = temp - socketstate.connecttime;
if ((b > 5000) || (socketstate.workstatus==false ))
{
Console.WriteLine("shut down the socket" + socketstate.workSocket.RemoteEndPoint.ToString());
socketstate.workSocket.Shutdown(SocketShutdown.Both);
socketstate.workSocket.Close();
socketstate.state = null;
socketstate.workSocket = null;
socketlist.Remove(socketstate);
}
}
}
GC.Collect();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void Monitor(List<socketstate> socketlist)
{
try
{

ThreadStart starter = delegate { MonitorCallback(socketlist); };
new Thread(starter).Start();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public static void AcceptCallback(IAsyncResult ar)
{

allDone.Set();
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
socketstate state = new socketstate();
try
{
state.workstatus = true;
state.workSocket = handler;
state.state = new StateObject();
state.workSocket = handler;
state.connecttime = System.Environment.TickCount;
state.state = new StateObject();
socketlist.Add(state);
handler.BeginReceive(state.state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
state.workstatus = false;
}
}
public static void ReadCallback(IAsyncResult ar)
{
String content = String.Empty;
socketstate state = (socketstate)ar.AsyncState;
Socket handler = state.workSocket;
try
{
int bytesRead = handler.EndReceive(ar);

if (bytesRead > 0)
{
state.state.sb.Append(Encoding.Unicode.GetString(state.state.buffer, 0, bytesRead));
content = state.state.sb.ToString();
if (content.IndexOf("<EOF>") > -1)
{
Console.WriteLine("Read {0} bytes from socket. \n Data : {1}",content.Length, content);
Send(handler, "<ENN>");
}
else
{
handler.BeginReceive(state.state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
state.workstatus = false;
}
}

private static void Send(Socket handler, String data)
{
try
{
byte[] byteData = Encoding.Unicode.GetBytes(data);
handler.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), handler);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void SendCallback(IAsyncResult ar)
{
try
{
Socket handler = (Socket)ar.AsyncState;
int bytesSent = handler.EndSend(ar);
Console.WriteLine("Sent {0} bytes to client.", bytesSent);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public static int Main(String[] args)
{
StartListening();
return 0;
}
}
}

110,525

社区成员

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

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

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