问题描述
如题,网上找了1个异步多线程的C#代码。可以实现客户端连接后客户端发送的数据再发送回去。但是我不知道怎么能把连接到这个服务器的客户端的IP显示出来,断开时候也有个提示,此外,比如说这个客户端连接了4个客户端,我想对第2个客户端主动发送数据怎么弄?求助usingSystem;usingSystem.Net;usingSystem.Net.Sockets;usingSystem.Text;usingSystem.Threading;//StateobjectforreadingclientdataasynchronouslypublicclassStateObject{//Clientsocket.publicSocketworkSocket=null;//Sizeofreceivebuffer.publicconstintBufferSize=1024;//Receivebuffer.publicbyte[]buffer=newbyte[BufferSize];//Receiveddatastring.publicStringBuildersb=newStringBuilder();}publicclassAsynchronousSocketListener{//Threadsignal.publicstaticManualResetEventallDone=newManualResetEvent(false);publicAsynchronousSocketListener(){}publicstaticvoidStartListening(){//Databufferforincomingdata.byte[]bytes=newByte[1024];//Establishthelocalendpointforthesocket.//TheDNSnameofthecomputer//runningthelisteneris"host.contoso.com".//IPHostEntryipHostInfo=Dns.Resolve(Dns.GetHostName());//IPAddressipAddress=ipHostInfo.AddressList[0];IPAddressipAddress=IPAddress.Parse("127.0.0.1");IPEndPointlocalEndPoint=newIPEndPoint(ipAddress,11000);//CreateaTCP/IPsocket.Socketlistener=newSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);//Bindthesockettothelocal//endpointandlistenforincomingconnections.try{listener.Bind(localEndPoint);listener.Listen(100);while(true){//Settheeventtononsignaledstate.allDone.Reset();//Startanasynchronoussockettolistenforconnections.Console.WriteLine("Waitingforaconnection...");listener.BeginAccept(newAsyncCallback(AcceptCallback),listener);//Waituntilaconnectionismadebeforecontinuing.allDone.WaitOne();}}catch(Exceptione){Console.WriteLine(e.ToString());}Console.WriteLine("nPressENTERtocontinue...");Console.Read();}publicstaticvoidAcceptCallback(IAsyncResultar){//Signalthemainthreadtocontinue.allDone.Set();//Getthesocketthathandlestheclientrequest.Socketlistener=(Socket)ar.AsyncState;Sockethandler=listener.EndAccept(ar);//Createthestateobject.StateObjectstate=newStateObject();state.workSocket=handler;handler.BeginReceive(state.buffer,0,StateObject.BufferSize,0,newAsyncCallback(ReadCallback),state);}publicstaticvoidReadCallback(IAsyncResultar){Stringcontent=String.Empty;//Retrievethestateobjectandthehandlersocket//fromtheasynchronousstateobject.StateObjectstate=(StateObject)ar.AsyncState;Sockethandler=state.workSocket;//Readdatafromtheclientsocket.intbytesRead=handler.EndReceive(ar);if(bytesRead>0){//Theremightbemoredata,sostorethedatareceivedsofar.state.sb.Append(Encoding.ASCII.GetString(state.buffer,0,bytesRead));//Checkforend-of-filetag.Ifitisnotthere,read//moredata.content=state.sb.ToString();if(content.IndexOf("<EOF>")>-1){//Allthedatahasbeenreadfromthe//client.Displayitontheconsole.Console.WriteLine("Read{0}bytesfromsocket.nData:{1}",content.Length,content);//Echothedatabacktotheclient.Send(handler,content);}else{//Notalldatareceived.Getmore.handler.BeginReceive(state.buffer,0,StateObject.BufferSize,0,newAsyncCallback(ReadCallback),state);}}}privatestaticvoidSend(Sockethandler,Stringdata){//ConvertthestringdatatobytedatausingASCIIencoding.byte[]byteData=Encoding.ASCII.GetBytes(data);//Beginsendingthedatatotheremotedevice.handler.BeginSend(byteData,0,byteData.Length,0,newAsyncCallback(SendCallback),handler);}privatestaticvoidSendCallback(IAsyncResultar){try{//Retrievethesocketfromthestateobject.Sockethandler=(Socket)ar.AsyncState;//Completesendingthedatatotheremotedevice.intbytesSent=handler.EndSend(ar);Console.WriteLine("Sent{0}bytestoclient.",bytesSent);handler.Shutdown(SocketShutdown.Both);handler.Close();}catch(Exceptione){Console.WriteLine(e.ToString());}}publicstaticintMain(String[]args){StartListening();return0;}}
解决方案
解决方案二:
用队列管理你的客户端连接,想怎么操作哪个客户端都行客户端IP可以通过客户端连接上来的socket.RemoteEndPoint获得
解决方案三:
socket.RemoteEndPoint这个就可以获取你远程客户端的IP等信息你可以在你接受客户连接的方法里面获取到客户端的IP同时你在这个方法里面把每个连接的客户端信息缓存起来这样你之后想给哪个客户端发送消息都可以了啊你可以以客户端IP地址作为键,客户端连接信息作为值进行缓存。
解决方案四:
引用2楼huangcailian的回复:
socket.RemoteEndPoint这个就可以获取你远程客户端的IP等信息你可以在你接受客户连接的方法里面获取到客户端的IP同时你在这个方法里面把每个连接的客户端信息缓存起来这样你之后想给哪个客户端发送消息都可以了啊你可以以客户端IP地址作为键,客户端连接信息作为值进行缓存。
可以按照上面那个给我写个简单的怎么缓冲客户端信息代码么?我是新手,不知道怎么写。
解决方案五:
引用1楼chuheiqian的回复:
用队列管理你的客户端连接,想怎么操作哪个客户端都行客户端IP可以通过客户端连接上来的socket.RemoteEndPoint获得
怎么缓冲发送呢?额,我只在网上搜到了如何打印出来,Console.WriteLine("connected:"+IPAddress.Parse(((IPEndPoint)handler.RemoteEndPoint).Address.ToString())+"port:"+((IPEndPoint)handler.RemoteEndPoint).Port.ToString());
解决方案六:
把连接上的客户端socket存到一个集合中,然后弄个列表把集合显示出来选那个客户端就向谁发消息呗不知道你要的是不是这样的功能,,
解决方案七:
这里有一大堆问题。随便说几个:1.服务器端不要写"127.0.0.1",要监听IPAddress.Any。2.服务器端尽量不要写Listen(100)。你可以写Listen(int.MaxValue),或者一个大于10000的数字。3.如果要写allDone.Set()语句,那么应该放到Sockethandler=listener.EndAccept(ar)语句后边。4.不要在intbytesRead=handler.EndReceive(ar)语句之后去把最近读到的一个数据包的内容当作一条消息。因为tcp为了保证通讯的“君子协定”,具有“沾包、分包”的特性。一次收到的内容,可能只有消息的一部分(而不是全部),也可能包括不止一个消息的内容。你的程序在这里的问题太严重了,这是一个极其严重的bug!关于你提的问题。在你得到所谓handler的时候,可以把它保存到你的AsynchronousSocketListener类声明的一个staticList<Socket>
的集合中(这并不是队列)。最后要说明的是,在.net中的Socket只是为了兼容linux风格的代码而已,它效率低,没有直接封装IOCP机制。在.net中,你应该使用TcpListener/TcpClient,而不是Socket类型!在windows下,不使用更高级IOCP机制而去使用普通的通用其它平台的Socket类,就显得“弱”了。
解决方案八:
通常,会自己封装一个Session类,而不是仅仅保持Socket集合。例如publicclassSession{publicstring授权唯一id;publicTcpClientClient;publicstring登录用户id;publicDateTime最后心跳时间;..........}publicclassAsynchronousSocketListener{staticList<Session>Clients=newList<Session>();........
解决方案九:
引用7楼sp1234的回复:
通常,会自己封装一个Session类,而不是仅仅保持Socket集合。例如publicclassSession{publicstring授权唯一id;publicTcpClientClient;publicstring登录用户id;publicDateTime最后心跳时间;..........}publicclassAsynchronousSocketListener{staticList<Session>Clients=newList<Session>();........
谢谢你了,我再去学习下,是C#新手,之前没弄过这个~