求教一下Socket Server程序在win7 64bit和xp 32bit下运行情况不一样的问题。

时间:2022-08-13 06:37:11
我程序里面的逻辑是这样的。accept客户端的连接后,就用下面的程序处理接收的数据,soc是SocketAsyncEventArgs。

if (soc.BytesTransferred > 0)
            {
                if (soc.SocketError == SocketError.Success)
                {
                    ////
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("接收的数据出错:\r\n{0}", ex.ToString());
                    }
                }
                else if (soc.SocketError != SocketError.Success) {
                    ////
                }
            }
            else {
                try
                {
                    Socket client = soc.AcceptSocket as Socket;                        
                    soc.Completed -= IOCompleted;
                    soc.Dispose();                    
                    string sessionId = client.Handle.ToString();
                    client.Shutdown(SocketShutdown.Both);
                    client.Disconnect(true);
                    this.socketClientSesson.Remove(client);
                    Console.WriteLine("客户端({0})已断开", sessionId);                                        
                }
                catch (Exception ex)
                {
                    Console.WriteLine("客户端已断开出错" + ex.ToString());
                    
                }
            }

程序在win7 64bit下面运行正常,但在xp 32bit下却有问题,程序刚开始运行,理论上还没有客户端连接的时候,就触发了处理接收数据的这段程序,并且触发了soc.BytesTransferred <= 0的条件,并报错:由于套接字没有连接并且(当使用一个 sendto 调用发送数据报套接字时)没有提供地址,发送或接收数据的请求没有被接受。

现在我在实际环境里是做了端口映射的,当在win 64bit下运行时,使用Server端的外网IP和内网IP都能连接,但在xp32bit下运行时,Server端就只能使用内网IP才能连接,是不是也和这个问题有关?

8 个解决方案

#1


你用了什么事件?放完整的代码,或者放伪代码说清楚逻辑

从这个代码片段里,根本看不出来它为什么会执行

#2


首先是服务端准备接收连接,args是SocketAsyncEventArgs

if (!socket.AcceptAsync(args))
                {
                    ProcessAccept(socket, args);
                }

客户端连接了之后,就执行ProcessAccept,准备接收客户端发过来的信息

            Socket client = s.AcceptSocket;            
            byte[] buf = new byte[1];                
            this.socketClientSesson.Add(client, buf);
            SocketAsyncEventArgs receiveArgs = new SocketAsyncEventArgs();
            receiveArgs.Completed += new EventHandler<SocketAsyncEventArgs>(IOCompleted);
            try
            {
                if (!client.ReceiveAsync(receiveArgs))
                {
                    this.ProcessReceive(receiveArgs);
                }                
            }
            catch (Exception ex) {
                Console.WriteLine(ex.ToString());
            }
            //接受下一个客户端的连接请求
            Socket server = (Socket)sender;
            s.AcceptSocket = null;
            if (!server.AcceptAsync(s))
            {
                this.ProcessAccept(server, s);
            }

客户端发过来信息后,就执行顶楼那一段代码。

在win7 64bit运行没问题,但在xp 32bit下就是服务端一开启后,就自动报错了:由于套接字没有连接并且(当使用一个 sendto 调用发送数据报套接字时)没有提供地址,发送或接收数据的请求没有被接受。

这时候如果是用Server端的内网地址和端口访问的话,还是能正常工作的。但是用外网地址和端口连接,就是持续报上面这个错。

#3


没看懂啊,AcceptAsync不是异步的吗,为什么ProcessAccept会紧跟在后面?

#4


你这还是把客户端和服务端的代码混杂在一起说
而且只贴出了函数里的代码,函数体呢
你不贴出函数体,怎么知道它什么时候会被调用呢

#5


你可以去掉无关的代码,只贴相关的代码
但是函数体不要丢啊
都不知道你把这代码放到什么函数里去,然后问题就是它执行了

那么它到底是什么,写没写错,跟它执行不执行又有什么关系
你需要把事件函数的函数定义,还有注册事件的代码,分别贴出来

#6


你的问题就是这段代码不应该一开始就执行,如此而已
那么这段代码到底是什么,根本无关紧要

你完全可以把你贴出的代码全部注释掉,换成
object debugPoint;
然后设置个断点,看它会不会执行

#7


Main函数里面调用Start方法

public void Start()
        {
            args = new SocketAsyncEventArgs();
            args.Completed += new EventHandler<SocketAsyncEventArgs>(ProcessAccept);
            var socketThread = new Thread(() =>
            {
                //定义Socket
               args.AcceptSocket = null;
                if (!socket.AcceptAsync(args))
                {
                    ProcessAccept(socket, args);
                }                            
            });
            socketThread.Start();            
        }


这是ProcessAccept

private void ProcessAccept(object sender, SocketAsyncEventArgs s) {
            Socket client = s.AcceptSocket;            
            SocketAsyncEventArgs receiveArgs = new SocketAsyncEventArgs();
            receiveArgs.Completed += new EventHandler<SocketAsyncEventArgs>(IOCompleted);
            receiveArgs.SetBuffer(new byte[1024], 0, 1024);
            receiveArgs.AcceptSocket = client;
            try
            {                
                if (!client.ReceiveAsync(receiveArgs))
                {
                    this.ProcessReceive(receiveArgs);
                }                
            }
            catch (Exception ex) {
                Console.WriteLine(ex.ToString());
            }
            Socket server = (Socket)sender;
            s.AcceptSocket = null;
            if (!server.AcceptAsync(s))
            {
                this.ProcessAccept(server, s);
            }            
        }


这是IOCompleted就是直接调用ProcessReceive,这下面就是ProcessReceive的代码。
private void ProcessReceive(SocketAsyncEventArgs soc) {
            if (soc.BytesTransferred > 0)
            {
                if (soc.SocketError == SocketError.Success)
                {
                    /////
                }
                    catch (Exception ex)
                    {
                        Console.WriteLine("接收的数据出错:\r\n{0}", ex.ToString());
                    }
                }
                else if (soc.SocketError != SocketError.Success) {
                    Socket client = soc.AcceptSocket as Socket;
                    soc.Completed -= IOCompleted;
                    soc.Dispose();
                    string sessionId = client.Handle.ToString();
                    client.Shutdown(SocketShutdown.Both);
                    client.Disconnect(true);
                    this.socketClientSesson.Remove(client);
                    Console.WriteLine("客户端({0})已断开", sessionId);
                }
            }
            else {
                try
                {
                    Socket client = soc.AcceptSocket as Socket;                        
                    soc.Completed -= IOCompleted;
                    soc.Dispose();
                    string sessionId = client.Handle.ToString();
                    client.Shutdown(SocketShutdown.Both);
                    client.Disconnect(true);
                    this.socketClientSesson.Remove(client);
                    Console.WriteLine("客户端({0})已断开", sessionId);                                        
                }
                catch (Exception ex)
                {
                    Console.WriteLine("客户端已断开出错" + ex.ToString());
                    
                }
            }
        }

#8


引用 6 楼 Z65443344 的回复:
你的问题就是这段代码不应该一开始就执行,如此而已
那么这段代码到底是什么,根本无关紧要

你完全可以把你贴出的代码全部注释掉,换成
object debugPoint;
然后设置个断点,看它会不会执行


我重新贴了一下。

#1


你用了什么事件?放完整的代码,或者放伪代码说清楚逻辑

从这个代码片段里,根本看不出来它为什么会执行

#2


首先是服务端准备接收连接,args是SocketAsyncEventArgs

if (!socket.AcceptAsync(args))
                {
                    ProcessAccept(socket, args);
                }

客户端连接了之后,就执行ProcessAccept,准备接收客户端发过来的信息

            Socket client = s.AcceptSocket;            
            byte[] buf = new byte[1];                
            this.socketClientSesson.Add(client, buf);
            SocketAsyncEventArgs receiveArgs = new SocketAsyncEventArgs();
            receiveArgs.Completed += new EventHandler<SocketAsyncEventArgs>(IOCompleted);
            try
            {
                if (!client.ReceiveAsync(receiveArgs))
                {
                    this.ProcessReceive(receiveArgs);
                }                
            }
            catch (Exception ex) {
                Console.WriteLine(ex.ToString());
            }
            //接受下一个客户端的连接请求
            Socket server = (Socket)sender;
            s.AcceptSocket = null;
            if (!server.AcceptAsync(s))
            {
                this.ProcessAccept(server, s);
            }

客户端发过来信息后,就执行顶楼那一段代码。

在win7 64bit运行没问题,但在xp 32bit下就是服务端一开启后,就自动报错了:由于套接字没有连接并且(当使用一个 sendto 调用发送数据报套接字时)没有提供地址,发送或接收数据的请求没有被接受。

这时候如果是用Server端的内网地址和端口访问的话,还是能正常工作的。但是用外网地址和端口连接,就是持续报上面这个错。

#3


没看懂啊,AcceptAsync不是异步的吗,为什么ProcessAccept会紧跟在后面?

#4


你这还是把客户端和服务端的代码混杂在一起说
而且只贴出了函数里的代码,函数体呢
你不贴出函数体,怎么知道它什么时候会被调用呢

#5


你可以去掉无关的代码,只贴相关的代码
但是函数体不要丢啊
都不知道你把这代码放到什么函数里去,然后问题就是它执行了

那么它到底是什么,写没写错,跟它执行不执行又有什么关系
你需要把事件函数的函数定义,还有注册事件的代码,分别贴出来

#6


你的问题就是这段代码不应该一开始就执行,如此而已
那么这段代码到底是什么,根本无关紧要

你完全可以把你贴出的代码全部注释掉,换成
object debugPoint;
然后设置个断点,看它会不会执行

#7


Main函数里面调用Start方法

public void Start()
        {
            args = new SocketAsyncEventArgs();
            args.Completed += new EventHandler<SocketAsyncEventArgs>(ProcessAccept);
            var socketThread = new Thread(() =>
            {
                //定义Socket
               args.AcceptSocket = null;
                if (!socket.AcceptAsync(args))
                {
                    ProcessAccept(socket, args);
                }                            
            });
            socketThread.Start();            
        }


这是ProcessAccept

private void ProcessAccept(object sender, SocketAsyncEventArgs s) {
            Socket client = s.AcceptSocket;            
            SocketAsyncEventArgs receiveArgs = new SocketAsyncEventArgs();
            receiveArgs.Completed += new EventHandler<SocketAsyncEventArgs>(IOCompleted);
            receiveArgs.SetBuffer(new byte[1024], 0, 1024);
            receiveArgs.AcceptSocket = client;
            try
            {                
                if (!client.ReceiveAsync(receiveArgs))
                {
                    this.ProcessReceive(receiveArgs);
                }                
            }
            catch (Exception ex) {
                Console.WriteLine(ex.ToString());
            }
            Socket server = (Socket)sender;
            s.AcceptSocket = null;
            if (!server.AcceptAsync(s))
            {
                this.ProcessAccept(server, s);
            }            
        }


这是IOCompleted就是直接调用ProcessReceive,这下面就是ProcessReceive的代码。
private void ProcessReceive(SocketAsyncEventArgs soc) {
            if (soc.BytesTransferred > 0)
            {
                if (soc.SocketError == SocketError.Success)
                {
                    /////
                }
                    catch (Exception ex)
                    {
                        Console.WriteLine("接收的数据出错:\r\n{0}", ex.ToString());
                    }
                }
                else if (soc.SocketError != SocketError.Success) {
                    Socket client = soc.AcceptSocket as Socket;
                    soc.Completed -= IOCompleted;
                    soc.Dispose();
                    string sessionId = client.Handle.ToString();
                    client.Shutdown(SocketShutdown.Both);
                    client.Disconnect(true);
                    this.socketClientSesson.Remove(client);
                    Console.WriteLine("客户端({0})已断开", sessionId);
                }
            }
            else {
                try
                {
                    Socket client = soc.AcceptSocket as Socket;                        
                    soc.Completed -= IOCompleted;
                    soc.Dispose();
                    string sessionId = client.Handle.ToString();
                    client.Shutdown(SocketShutdown.Both);
                    client.Disconnect(true);
                    this.socketClientSesson.Remove(client);
                    Console.WriteLine("客户端({0})已断开", sessionId);                                        
                }
                catch (Exception ex)
                {
                    Console.WriteLine("客户端已断开出错" + ex.ToString());
                    
                }
            }
        }

#8


引用 6 楼 Z65443344 的回复:
你的问题就是这段代码不应该一开始就执行,如此而已
那么这段代码到底是什么,根本无关紧要

你完全可以把你贴出的代码全部注释掉,换成
object debugPoint;
然后设置个断点,看它会不会执行


我重新贴了一下。