异步socket的线程分配(C#)

本文通过一个异步Socket编程示例,详细介绍了线程如何被分配到连接、接收和发送操作中。展示了异步Socket如何利用线程池进行高效通信,并通过代码演示了线程的后台属性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

异步socket的线程分配(C#)
 

    以下是MSDN里异步socket示例的代码,我在代码里加入了显示当前线程ID的语句,想看看异步socket的线程是怎么分配的,与客户端配合运行后的结果如图
  


Server端代码:
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;


namespace ConsoleServer
{
    
public class StateObject 
    
{
        
// Client  socket.
        public Socket workSocket = null;
        
// Size of receive buffer.
        public const int BufferSize = 1024;
        
// Receive buffer.
        public byte[] buffer = new byte[BufferSize];
        
// Received data string.
        public StringBuilder sb = new StringBuilder();  
    }



    
class Program
    
{
        
public static ManualResetEvent allDone = new ManualResetEvent(false);
        
        
/// <summary>
        
///监听
        
/// 并开始接受网络连接请求的方法
        
/// </summary>

        public static void StartListening()
        
{
            Console.WriteLine(
"监听时的线程:" + Thread.CurrentThread.ManagedThreadId.ToString());
            
// Data buffer for incoming data.
            byte[] bytes = new Byte[1024];

            
// Establish the local endpoint for the socket.
            
// The DNS name of the computer
            
// running the listener is "host.contoso.com".
            IPHostEntry ipHostInfo = Dns.Resolve("127.0.0.1");
            IPAddress ipAddress 
= ipHostInfo.AddressList[0];
            IPEndPoint localEndPoint 
= new IPEndPoint(ipAddress, 9090);

            
// 创建一个tcp/ip socket
            Socket listener = new Socket(AddressFamily.InterNetwork,
                SocketType.Stream, ProtocolType.Tcp);

            
// Bind the socket to the local endpoint and listen for incoming connections.
            try
            
{
                listener.Bind(localEndPoint);
                Console.WriteLine(
"Listen1: " + Thread.CurrentThread.ManagedThreadId.ToString());
                listener.Listen(
100);
                Console.WriteLine(
"Listen2:  " + Thread.CurrentThread.ManagedThreadId.ToString());

                
while (true)
                
{
                    Console.WriteLine(
"1:  " + Thread.CurrentThread.ManagedThreadId.ToString());
                    
// Set the event to nonsignaled state.设置为无信号状态
                    allDone.Reset();
                    Console.WriteLine(
"2: " + Thread.CurrentThread.ManagedThreadId.ToString());
                    
// Start an asynchronous socket to listen for connections.
                    Console.WriteLine("Waiting for a connection");
                    
//开始建立连接
                    listener.BeginAccept(
                        
new AsyncCallback(AcceptCallback),
                        listener);
                    Console.WriteLine(
"3:  " + Thread.CurrentThread.ManagedThreadId.ToString());
                    
// Wait until a connection is made before continuing.

                    allDone.WaitOne();
                    Console.WriteLine(
"4: " + Thread.CurrentThread.ManagedThreadId.ToString());
                }


            }

            
catch (Exception e)
            
{
                Console.WriteLine(e.ToString());
            }


            Console.WriteLine(
"/nPress ENTER to continue");
            Console.Read();

        }


        
/// <summary>
        
/// 处理连接请求
        
/// 并开始接收网络数据的回调方法
        
/// </summary>
        
/// <param name="ar"></param>

        public static void AcceptCallback(IAsyncResult ar)      
        
{
            
// Signal the main thread to continue.
            allDone.Set();
            Console.WriteLine(
"AcceptCallback1线程ID为:  "+ Thread.CurrentThread.ManagedThreadId.ToString());
            
// Get the socket that handles the client request.
            Socket listener = (Socket)ar.AsyncState;
            
//建立socket通道,连接建立完成
            Socket handler = listener.EndAccept(ar);
            
            
// Create the state object.创建一个状态对象,开始接受数据
            StateObject state = new StateObject();
            state.workSocket 
= handler;
            handler.BeginReceive(state.buffer, 
0, StateObject.BufferSize, 0,
                
new AsyncCallback(ReadCallback), state);
            Console.WriteLine(
"AcceptCallback2线程ID为:   " + Thread.CurrentThread.ManagedThreadId.ToString());
        }



        
/// <summary>
        
/// 结束接收数据的回调方法
        
/// </summary>
        
/// <param name="ar"></param>

        public static void ReadCallback(IAsyncResult ar)
        
{
            Console.WriteLine(
"ReadCallback线程ID为:   " + Thread.CurrentThread.ManagedThreadId.ToString());
            String content 
= String.Empty;

            
// Retrieve the state object and the handler socket
            
// from the asynchronous state object.
            StateObject state = (StateObject)ar.AsyncState;
            Socket handler 
= state.workSocket;

            
// Read data from the client socket.从socket通道里读取数据
            int bytesRead = handler.EndReceive(ar);

            
if (bytesRead > 0)
            
{
                
// There  might be more data, so store the data received so far.
                state.sb.Append(Encoding.ASCII.GetString(
                    state.buffer, 
0, bytesRead));

                
// Check for end-of-file tag. If it is not there, read 
                
// more data.
                content = state.sb.ToString();
                
if (content.IndexOf("<EOF>"> -1)
                
{
                    
// All the data has been read from the 
                    
// client. Display it on the console.
                    Console.WriteLine("Read {0} bytes from socket. /n Data : {1}",
                        content.Length, content);

                    Console.WriteLine(
"请输入要发送的信息:");
                    
string str = Console.ReadLine();
                    Send(handler, str 
+ "<EOF>");

                    
//Send(handler, content);
                    
                    
                }

                
else
                
{
                    
// Not all data received. Get more.
                    handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                    
new AsyncCallback(ReadCallback), state);
                }

            }

        }



        
/// <summary>
        
/// 开始发送数据的方法
        
/// </summary>
        
/// <param name="handler"></param>
        
/// <param name="data"></param>

        private static void Send(Socket handler, String data)
        
{
            
// Convert the string data to byte data using ASCII encoding.
            byte[] byteData = Encoding.ASCII.GetBytes(data);

            
// Begin sending the data to the remote device.
            handler.BeginSend(byteData, 0, byteData.Length, 0,
                
new AsyncCallback(SendCallback), handler);
        }



        
/// <summary>
        
/// 结束发送数据的回调方法
        
/// </summary>
        
/// <param name="ar"></param>

        private static void SendCallback(IAsyncResult ar)
        
{
            Console.WriteLine(
"SendCallback线程ID为:   " + Thread.CurrentThread.ManagedThreadId.ToString());
            
try
            
{
                
// Retrieve the socket from the state object.
                Socket handler = (Socket)ar.AsyncState;

                
// Complete sending the data to the remote device.
                int bytesSent = handler.EndSend(ar);
                Console.WriteLine(
"Sent {0} bytes to client.", bytesSent);

                
//没有了这两句,server是发不出去的,为什么呢?
                handler.Shutdown(SocketShutdown.Both);
                handler.Close();

            }

            
catch (Exception e)
            
{
                Console.WriteLine(e.ToString());
            }

        }



        
static void Main(string[] args)
        
{
            Console.WriteLine(
"main线程ID为:   " + Thread.CurrentThread.ManagedThreadId.ToString());
            StartListening();
            Console.ReadLine();
        }

    }

}




客户端代码:
using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Net;


namespace WindowsClient
{
    
public class StateObject
    
{
        
// Client socket.
        public Socket workSocket = null;
        
// Size of receive buffer.
        public const int BufferSize = 256;
        
// Receive buffer.
        public byte[] buffer = new byte[BufferSize];
        
// Received data string.
        public StringBuilder sb = new StringBuilder();
    }



   
class Program
   
{
        
// The port number for the remote device.
        private const int port = 9090;
        

        
// ManualResetEvent instances signal completion.
        private static ManualResetEvent connectDone = 
            
new ManualResetEvent(false);
        
private static ManualResetEvent sendDone = 
            
new ManualResetEvent(false);
        
private static ManualResetEvent receiveDone = 
            
new ManualResetEvent(false);

        
// The response from the remote device.
        private static String response = String.Empty;

        
private static void StartClient() 
        
{
            
string str = string.Empty;
            
// Connect to a remote device.
            try {
                
// Establish the remote endpoint for the socket.
                
// The name of the 
                
// remote device is "host.contoso.com".
                IPHostEntry ipHostInfo = Dns.Resolve("127.0.0.1");
                IPAddress ipAddress 
= ipHostInfo.AddressList[0];
                IPEndPoint remoteEP 
= new IPEndPoint(ipAddress, port);

                
// Create a TCP/IP socket.
                Socket client = new Socket(AddressFamily.InterNetwork,
                    SocketType.Stream, ProtocolType.Tcp);

                
// Connect to the remote endpoint.
                client.BeginConnect( remoteEP,
                    
new AsyncCallback(ConnectCallback), client);
                connectDone.WaitOne();
                Console.WriteLine(
"请输入要发送的信息:");
               
// str = Console.ReadLine();
                
// Send test data to the remote device.
                Send(client, str + "<EOF>");//"This is a test<EOF>");
                sendDone.WaitOne();
               
                
// Receive the response from the remote device.
                Receive(client);
                receiveDone.WaitOne();
                
                
// Write the response to the console.
                Console.WriteLine("Response received : {0}", response);

                
// Release the socket.
                client.Shutdown(SocketShutdown.Both);
                client.Close();
                
            }
 
            
catch (Exception e) 
            
{
                Console.WriteLine(e.ToString());
            }

        }


        
private static void ConnectCallback(IAsyncResult ar) 
        
{
            
try 
            
{
                
// Retrieve the socket from the state object.
                Socket client = (Socket) ar.AsyncState;

                
// Complete the connection.
                client.EndConnect(ar);

                Console.WriteLine(
"Socket connected to {0}",
                    client.RemoteEndPoint.ToString());

                
// Signal that the connection has been made.
                connectDone.Set();
            }
 
            
catch (Exception e) 
            
{
                Console.WriteLine(e.ToString());
            }

        }



        
private static void Receive(Socket client)
        
{
            
try 
            
{
                
// Create the state object.
                StateObject state = new StateObject();
                state.workSocket 
= client;

                
// Begin receiving the data from the remote device.
                client.BeginReceive( state.buffer, 0, StateObject.BufferSize, 0,
                    
new AsyncCallback(ReceiveCallback), state);
            }
 
            
catch (Exception e) 
            
{
                Console.WriteLine(e.ToString());
            }

        }



        
private static void ReceiveCallback( IAsyncResult ar )
        
{
            
try 
            
{
                
// Retrieve the state object and the client socket 
                
// from the asynchronous state object.
                StateObject state = (StateObject) ar.AsyncState;
                Socket client 
= state.workSocket;

                
// Read data from the remote device.
                int bytesRead = client.EndReceive(ar);

                
if (bytesRead > 0
                
{
                    
// There might be more data, so store the data received so far.
                state.sb.Append(Encoding.ASCII.GetString(state.buffer,0,bytesRead));

                    
// Get the rest of the data.
                    client.BeginReceive(state.buffer,0,StateObject.BufferSize,0,
                        
new AsyncCallback(ReceiveCallback), state);
                }
 
                
else 
                
{
                    
// All the data has arrived; put it in response.
                    if (state.sb.Length > 1
                    
{
                        response 
= state.sb.ToString();
                    }

                    
// Signal that all bytes have been received.
                    receiveDone.Set();
                }

            }
 
            
catch (Exception e) 
            
{
                Console.WriteLine(e.ToString());
            }

        }



        
private static void Send(Socket client, String data) 
        
{
            
// Convert the string data to byte data using ASCII encoding.
            byte[] byteData = Encoding.ASCII.GetBytes(data);

            
// Begin sending the data to the remote device.
            client.BeginSend(byteData, 0, byteData.Length, 0,
                
new AsyncCallback(SendCallback), client);
        }


        
private static void SendCallback(IAsyncResult ar) 
        
{
            
try 
            
{
                
// Retrieve the socket from the state object.
                Socket client = (Socket) ar.AsyncState;

                
// Complete sending the data to the remote device.
                int bytesSent = client.EndSend(ar);
                Console.WriteLine(
"Sent {0} bytes to server.", bytesSent);

                
// Signal that all bytes have been sent.
                sendDone.Set();
            }
 
            
catch (Exception e) 
            
{
                Console.WriteLine(e.ToString());
            }

        }
 

   
        
static void Main(string[] args)
        
{
            StartClient();
            Console.ReadLine();
        }

    }

}



 

根据MSDN的原话:

异步套接字使用系统线程池中的线程处理传入的连接。

一个线程负责接受连接,

另一线程用于处理每个传入的连接,

还有一个线程负责接收连接数据。

这些线程可以是同一个线程,具体取决于线程池所分配的线程。”

个人理解:根据MSDN对异步socket连接、接受、发送等线程分配的解释,以及上面代码的注释和演示,我们在做异步socket编程时,不用对socket这组线程做任何处理,只要处理好主线程及其它线程与socket这周线程的关系就可。


 

补充main方法和AcceptCallback方法里分别加入
bool threadBool = Thread.CurrentThread.IsBackground;
Console.WriteLine(threadBool.ToString());
这两条语句,则会发现main方法里线程的IsBackground属性为falseAcceptCallback方法里线程的IsBackground属性为TrueMSDN里说:“托管线程池中的线程为后台线程,即它们的 IsBackground 属性为 true”;再根据上面引用的MSDN的原文“这些线程可以是同一个线程,具体取决于线程池所分配的线程。”的这一句可知,此线程就是由线程池所分配的,也许有人会认为此补充为多此一举,但是我最初对于这几个线程的出现,以及MSDN的解释没有很好的理解,所以出现了这个补充,现在好了,我知道了这几个隐藏的线程出自那里了,呵呵,你呢?

再次补充:
//如果要查看线程是否属于托管线程池,可使用
   bool poolThread = Thread.CurrentThread.IsThreadPoolThread;//指示线程是否属于托管线程池

希望对异步
socket 及线程了解比较深入的同学,能给出更多的建议和指导
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值