多线程socket中,每一个线程用异步后,出现的问题

问题描述

开始我为了接收多个端口收到的UDP包数据,我创建了多个线程,但当UDP包发送很快时,接收就会丢包,后来我在多个线程中用了异步的方法,如下代码所示,多线程执行StartListening()方法,在StartListening()方法中执行了ReadCallback(IAsyncResultar),可是我发现,在我跟踪到ReadCallback(IAsyncResultar)中时,发现只有一个ReadCallback线程(从vs2005开发环境中的线程监视中看到的),难道多个线程执行StartListening()方法,并不能产生多个ReadCallback线程吗?请各位高手指点,急待解决!!usingSystem;usingSystem.Net;usingSystem.Net.Sockets;usingSystem.Text;usingSystem.Threading;usingSystem.Data;usingSystem.Data.SqlClient;//StateobjectforreadingclientdataasynchronouslypublicclassStateObject{//Clientsocket.publicSocketworkSocket=null;//Sizeofreceivebuffer.publicconstintBufferSize=255;//Receivebuffer.publicbyte[]buffer=newbyte[BufferSize];//Receiveddatastring.publicStringBuildersb=newStringBuilder();}publicclassAsynchronousSocketListener{//Incomingdatafromclient.publicstaticstringdata=null;//Threadsignal.publicstaticManualResetEventallDone=newManualResetEvent(false);publicstaticintCount=1;publicAsynchronousSocketListener(){}publicstaticvoidStartListening(){byte[]bytes=newByte[255];IPHostEntryipHostInfo=Dns.Resolve(Dns.GetHostName());IPAddressipAddress=ipHostInfo.AddressList[0];IPEndPointlocalEndPoint=newIPEndPoint(ipAddress,2020);Socketlistener=newSocket(AddressFamily.InterNetwork,SocketType.Dgram,ProtocolType.Udp);try{listener.Bind(localEndPoint);IPEndPointsender=newIPEndPoint(IPAddress.Any,0);EndPointtempRemoteEP=(EndPoint)sender;try{while(true){allDone.Reset();StateObjectso2=newStateObject();so2.workSocket=listener;listener.BeginReceiveFrom(so2.buffer,0,StateObject.BufferSize,0,reftempRemoteEP,newAsyncCallback(ReadCallback),so2);allDone.WaitOne();}}catch(Exceptione){Console.WriteLine(e.ToString());}}catch(Exceptione){Console.WriteLine(e.ToString());}Console.WriteLine("nPressENTERtocontinue...");Console.Read();}publicstaticvoidReadCallback(IAsyncResultar){allDone.Set();StateObjectso=(StateObject)ar.AsyncState;Sockets=so.workSocket;so.sb.Remove(0,so.sb.Length);IPEndPointsender=newIPEndPoint(IPAddress.Any,0);EndPointtempRemoteEP=(EndPoint)sender;intread=s.EndReceiveFrom(ar,reftempRemoteEP);if(read>0){//so.sb.Append(Encoding.ASCII.GetString(so.buffer,0,read));//so.sb.Append(Encoding.Default.GetString(so.buffer,0,read));for(inti=0;i<read;i++){so.sb.Append(string.Format("{0:X2}",so.buffer[i]));}}else{}if(so.sb.Length>1){//Allthedatahasbeenread,sodisplaysittotheconsole.stringstrContent;strContent=so.sb.ToString();Count=Count+1;Console.WriteLine(String.Format("Count{0}Read{1}bytefromsocket"+"data={2}",Count,strContent.Length,strContent));if(strContent.IndexOf("454F46")>=0)//挂断指令{s.Close();//问题出现了,一挂断就出错}}}privatestaticvoidSend(Sockethandler,EndPointremoteEP,Stringdata){//ConvertthestringdatatobytedatausingASCIIencoding.byte[]byteData=Encoding.ASCII.GetBytes(data);handler.BeginSendTo(byteData,0,byteData.Length,0,remoteEP,newAsyncCallback(SendCallback),handler);}privatestaticvoidSendCallback(IAsyncResultar){try{Sockethandler=(Socket)ar.AsyncState;intbytesSent=handler.EndSend(ar);}catch(Exceptione){Console.WriteLine(e.ToString());}}publicstaticintMain(String[]args){StartListening();return0;}}

解决方案

解决方案二:
当然不会有多个ReadCallBack(),这个回调只在接收成功后才调用,并不是在接收的时候调用。所以你只能看到一个ReadCallBack()。因为其它的接收还堵在那里呢。
解决方案三:
代码比较多,没仔细看。其实你的代码并没有太大的问题,之所以出现丢包是因为你同步信号释放的时机不对。ReadCallback(IAsyncResultar)回调方法中你第一时间就释放了allDone,这虽然能够第一时间给接收的线程一个信号让其马上开始下一次循环,但你没注意到,其实这个时候listener还是停留在上次的阻塞状态,在listener.EndReceiveFrom(ar,reftempRemoteEP)方法没执行之前,listener无法接受新的数据,所以,数据发送快了时候自然会丢包。解决办法很简单,allDone.Set()放到intread=s.EndReceiveFrom(ar,reftempRemoteEP)后面执行即可。其实你这个程序没必要异步接收的,反正你的主线程都是经常性地阻塞去监听的,把listener.BeginReceiveFrom改为同步接收:listener.ReceiveFrom然后在开一条新线程处理接收的数据岂不更简单直观?这样你就不需要引入ManualResetEvent手动同步类了。最后需要指明的是,你这样的异步方法任何时候都只是一条ReadCallback线程,vs2005的显示是正确的,异步的本质就是开一条新的县城去同步接收而已。
解决方案四:
s.close()出现的问题应该是系统会强制抛出一个异常,大致的信息应该是:“远程主机强制关闭了一个现有的连接”之类的。。。把s.close()放到try..catch语句里面就可以了。

时间: 2024-12-01 14:55:40

多线程socket中,每一个线程用异步后,出现的问题的相关文章

视频传输-android开发中中断一个线程

问题描述 android开发中中断一个线程 我有一个APP程序是用来视频传输的,里面有一个的线程是打开摄像头,采集视频并发送出去,我想问,当这个线程开始了,我怎么才能关闭它,也就是关闭摄像头并不再传输视频流? 解决方案 定个flage,把flag设为false结束线程

代码-求助各位大神LIstfragment中,分线程获取数据后刷新界面崩溃,用分线程加载数据后

问题描述 求助各位大神LIstfragment中,分线程获取数据后刷新界面崩溃,用分线程加载数据后 如题:代码如下,要在viewpager中的一个fragment中加载一个listview,用分线程加载数据后,handleMessage给成员变量的集合赋值后,notify,会直接崩溃 /** 报警图片 */ public class AlarmPhotoFragment extends ListFragment { private int mType = 0; private ListView

多线程-JAVA中如何在一个线程里面停掉另一个线程

问题描述 JAVA中如何在一个线程里面停掉另一个线程 JAVA中如何在一个线程里面停掉另一个线程,是在一个线程里面哦 PS:新人第一次问问题,希望大神求教 解决方案 定义一个共享变量在run方法里面 while(start){ } 解决方案二: 所以说,这个问题的答案是:不可以! 虽然的确有那么个方法可以摧毁别人的线程,但很早很早就已经过期了,如果没记错的话我之前也这么玩,而结果是这个过期的方法根本没有作用-- 虽然说办法不是没有,那就是通过改变变量值,它知道自己该死了,就退出循环,走向结束.

详解Java多线程编程中CountDownLatch阻塞线程的方法_java

直译过来就是倒计数(CountDown)门闩(Latch).倒计数不用说,门闩的意思顾名思义就是阻止前进.在这里就是指 CountDownLatch.await() 方法在倒计数为0之前会阻塞当前线程. CountDownLatch是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待. CountDownLatch 的作用和 Thread.join() 方法类似,可用于一组线程和另外一组线程的协作.例如,主线程在做一项工作之前需要一系列的准备工作,只有这些准备工

C#多线程中怎么样把一个线程得到的值传给另一个线程

问题描述 是C/S的程序,启动一个线程得到DataSet后将其怎样传给第二个线程使用. 解决方案 解决方案二:做线程共享资源,然后用锁定机制来管理.lock(){}Mutex....MonitorInterLocked等解决方案三:不好意思能说的清楚点吗?不太明白.解决方案四:只要你能保证不会存在多个线程同时读写这个对象(同时读没问题),你爱怎么传怎么传1楼给你的是你出现多个线程需要读写的的时候,如何同步,来保证多线程之间不会同时(而是有顺序的)读写该对象解决方案五:委托!但是你要注意多线程的线

linux多线程编程中如何等待过个线程退出

问题描述 linux多线程编程中如何等待过个线程退出 linux多线程编程中,如果线程A创建了线程B,我知道用pthread__ join可以令线程A 阻塞然后等待线程B的退出.如果线程A创建了三个线程B,C,D,执行完的先后顺序不知.想让A必须等待三个线程都退出后再退出,应该怎么做? 连用pthread__join三次吗???但是第一次用了pthread__join后,A不就阻塞了吗? 解决方案 多线程编程(一):线程创建和退出Linux多线程编程(创建线程)Linux多线程编程(创建线程)

VB.NET中使用代表对方法异步调用

异步 按照我们常规的思维方式,计算机应该是干完一件事,然后再干下一件.用术语来说,这种执行任务的方式叫做同步执行(Synchronous Execution).既然这样,那么为什么要引入异步执行的概念呢? 目录 为什么要使用异步调用实现异步调用的步骤和机理 为什么要使用异步调用(Asynchronous Method Execution) 按照我们常规的思维方式,计算机应该是干完一件事,然后再干下一件.用术语来说,这种执行任务的方式叫做同步执行(Synchronous Execution).既然

服务器-java中把Socket.accept放入多线程中 如果一个客户端连入 那么会接入哪一个线程中呢

问题描述 java中把Socket.accept放入多线程中 如果一个客户端连入 那么会接入哪一个线程中呢 如题 自己测试出来是连接不到 不明白 ................... .................... 解决方案 linux C中的accept函数它的其中一个参数struct sockaddr是一个结构体,该结构体中的一个字段记录了连接上来的客户端的IP地址和端口号等信息, 你只需要访问该结构体中的这个字段就好了 accept( SOCKET s, struct sock

多线程中操作数据库,resultset还未结束当前操作,己被另一个线程提前关闭而出错

问题描述 先来看我的线程 private DataHandle dh = new DataHandle(); public synchronized void runTask() { try { dh.handle(pbean.getStartNo(), pbean.getEndNo()); } catch (Exception e) { e.printStackTrace(); // TaskManagerBean.returnItem(); } 这个是我的线程,里面用到一个叫DataHand