Socket的使用
要通过互联网进行通信,至少需要一对Socket,其中一个为ClientSocket客户端使用,另一个ServerSocket服务器端使用,两Socket连接过程分三步骤:
1)服务器监听Listening;ServerSocket并不定位具体的客户端Socket,而是处于等待连接状态,实时监控网络状态。
2)客户端请求Request;ClientSocket发出连接请求(Connect Request),要连接的目标是服务器端的Socket。ClientSocket首先必须描述它要连接的ServerSocket,指出ServerSocket的地址(如IPv4或IPv6)和端口号Port,然后就向ServerSocket发出连接请求。
3)连接确认;当ServerSocket监听到或者接收到ClientSocket的连接请求,它就响应ClientSocket的请求,建立一个新的线程来处理此请求,然后把ServerSocket的描述发给客户端,一旦客户端确认了此描述,连接就成功建立。而ServerClient继续处于监听状态,继续接收其他ClientSocket的连接请求(因为每次请求都是交给新线程来处理的)。
.Net中Socket的命名空间:System.Net.Sockets
网络协议的命名空间:System.Net
以下是一些例子:
(1)利用Socket发送一个Http请求:
这里只使用到一个ClientSocket;主要反应了三步骤中的第(2)(3)两步骤;SeverSocket由Web服务器来扮演。
(2)基于C/S架构的同步Socket示例
在这里可以看到ServerSocket和ClientSocket的演示,并完全体现三个步骤(1)(2)(3)中.Net中的实现。
同步方式主要使用:Accept、Receive、Send三个同步方法。
同步方式:发送方发送数据包后,不等待接收方响应就立即接着发送下一个数据包。
使用此方式,Client或Server执行Socket连接、接收、发送操作时,Client或Server会中止工作,处于暂停状态。编程较简单,当对于需要网络操作比较繁重的时候并不太适合,此时需要采用异步方式。
1)对于Server的同步方式,在连接请求到来之前,ServerSocket一直处于Listen状态,而服务器则处于中止等待状态;当连接请求到来后,ServerSocket调用Accept方法,返回一个与ClientSocket相连的Socket处理此请求。直到请求完成后ServerSocket才继续监听等待。因为同步方式只使用一个线程来处理监听请求和响应请求。
2)Client的同步方式,ClientSocket负责发出连接请求和请求数据,并接收返回的数据。同样是在单线程中处理请求和处理返回数据。
测试如下:
(3)基于C/S架构的异步Socket示例
异步方式对应有:BeginAccept、EndAccept,BeginReceive、EndReceive,BeginSend、EndSend等方法。
异步方式:发送方发送一个数据包后,一直等到接收方响应后,才接着发送下一个数据包。
1)异步服务器端AsyncServer,异步Socket可在监听同时进行其他操作,如发送数据和读取数据。对于网络操作负荷比较大的程序来说特别适合。
对于异步ServerSocket,需要一个方法开始接受网络连接请求,一个回调方法AcceptCallback处理连接请求,一个回调方法ReceiveCallback处理接收数据,一个回调方法SendCallback处理发送数据。
使用之前编写的同步客户端SyncClient访问上面的异步服务器端AsyncServer,测试如下:
2)异步客户端AsyncClient
测试如下:
(4)总结:
只要明白Socket的工作原理,即三步骤,就可以轻松地利用Socket编写网络程序。
1)服务器监听Listening;ServerSocket并不定位具体的客户端Socket,而是处于等待连接状态,实时监控网络状态。
2)客户端请求Request;ClientSocket发出连接请求(Connect Request),要连接的目标是服务器端的Socket。ClientSocket首先必须描述它要连接的ServerSocket,指出ServerSocket的地址(如IPv4或IPv6)和端口号Port,然后就向ServerSocket发出连接请求。
3)连接确认;当ServerSocket监听到或者接收到ClientSocket的连接请求,它就响应ClientSocket的请求,建立一个新的线程来处理此请求,然后把ServerSocket的描述发给客户端,一旦客户端确认了此描述,连接就成功建立。而ServerClient继续处于监听状态,继续接收其他ClientSocket的连接请求(因为每次请求都是交给新线程来处理的)。
.Net中Socket的命名空间:System.Net.Sockets
网络协议的命名空间:System.Net
以下是一些例子:
(1)利用Socket发送一个Http请求:
这里只使用到一个ClientSocket;主要反应了三步骤中的第(2)(3)两步骤;SeverSocket由Web服务器来扮演。
HttpGetRequest
public static string HttpGetRequest(string url)
{
//set request data
Encoding ASCII = Encoding.ASCII;
string getRequest = "GET / HTTP/1.1\r\nHost: " + url + "\r\nConnection: Close\r\n\r\n";
//Convert request string to bytes
byte[] requestBytes = ASCII.GetBytes(getRequest);
//set recvice buffer size as 256 bytes
byte[] recvBytes = new byte[256];
// the return page
string recvicePageHtml = "";
//IPAddress is the IP address and IPEndPoint is the Port
//using the DNS to get the first IP Address
IPHostEntry host;
IPAddress hostIP;
IPEndPoint hostPort;
try
{
host = Dns.GetHostEntry(url);
hostIP = host.AddressList[0];
hostPort = new IPEndPoint(hostIP, 80);
}
catch(Exception e)
{
recvicePageHtml = e.Message;
return recvicePageHtml;
}
//Create the Client Socket use TCP and Stream to send the http request
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//send the Connect Request, if connect success, then continue
clientSocket.Connect(hostPort);
if (!clientSocket.Connected)
{
recvicePageHtml = "Unable to get the Web";
return recvicePageHtml;
}
//send the Http Get Reqeust
clientSocket.Send(requestBytes, requestBytes.Length, SocketFlags.None);
Single totalSize = 0;
int recvDataSize = clientSocket.Receive(recvBytes, recvBytes.Length, SocketFlags.None);
recvicePageHtml = "Default Html Page on [" + host.HostName + ":" + host.AddressList[0] + "]:\r\n\r\n";
recvicePageHtml += ASCII.GetString(recvBytes, 0, recvDataSize);
while (recvDataSize > 0)
{
totalSize += recvDataSize;
recvDataSize = clientSocket.Receive(recvBytes, recvBytes.Length, SocketFlags.None);
recvicePageHtml += ASCII.GetString(recvBytes, 0, recvDataSize);
}
recvicePageHtml += "\r\n\r\nTotal Recvice " + totalSize + " bytes";
return recvicePageHtml;
}
public static string HttpGetRequest(string url)
{
//set request data
Encoding ASCII = Encoding.ASCII;
string getRequest = "GET / HTTP/1.1\r\nHost: " + url + "\r\nConnection: Close\r\n\r\n";
//Convert request string to bytes
byte[] requestBytes = ASCII.GetBytes(getRequest);
//set recvice buffer size as 256 bytes
byte[] recvBytes = new byte[256];
// the return page
string recvicePageHtml = "";
//IPAddress is the IP address and IPEndPoint is the Port
//using the DNS to get the first IP Address
IPHostEntry host;
IPAddress hostIP;
IPEndPoint hostPort;
try
{
host = Dns.GetHostEntry(url);
hostIP = host.AddressList[0];
hostPort = new IPEndPoint(hostIP, 80);
}
catch(Exception e)
{
recvicePageHtml = e.Message;
return recvicePageHtml;
}
//Create the Client Socket use TCP and Stream to send the http request
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//send the Connect Request, if connect success, then continue
clientSocket.Connect(hostPort);
if (!clientSocket.Connected)
{
recvicePageHtml = "Unable to get the Web";
return recvicePageHtml;
}
//send the Http Get Reqeust
clientSocket.Send(requestBytes, requestBytes.Length, SocketFlags.None);
Single totalSize = 0;
int recvDataSize = clientSocket.Receive(recvBytes, recvBytes.Length, SocketFlags.None);
recvicePageHtml = "Default Html Page on [" + host.HostName + ":" + host.AddressList[0] + "]:\r\n\r\n";
recvicePageHtml += ASCII.GetString(recvBytes, 0, recvDataSize);
while (recvDataSize > 0)
{
totalSize += recvDataSize;
recvDataSize = clientSocket.Receive(recvBytes, recvBytes.Length, SocketFlags.None);
recvicePageHtml += ASCII.GetString(recvBytes, 0, recvDataSize);
}
recvicePageHtml += "\r\n\r\nTotal Recvice " + totalSize + " bytes";
return recvicePageHtml;
}
Main
static void Main(string[] args)
{
//Console.Write(HttpGetRequest("www.gdut.edu.cn"));
//Console.Write(HttpGetRequest("www.net4.com.cn"));
//Console.Write(HttpGetRequest("ftp.net42.com.cn"));
Console.Write(HttpGetRequest("192.168.0.1"));
Console.Read();
}
测试如下:static void Main(string[] args)
{
//Console.Write(HttpGetRequest("www.gdut.edu.cn"));
//Console.Write(HttpGetRequest("www.net4.com.cn"));
//Console.Write(HttpGetRequest("ftp.net42.com.cn"));
Console.Write(HttpGetRequest("192.168.0.1"));
Console.Read();
}
(2)基于C/S架构的同步Socket示例
在这里可以看到ServerSocket和ClientSocket的演示,并完全体现三个步骤(1)(2)(3)中.Net中的实现。
同步方式主要使用:Accept、Receive、Send三个同步方法。
同步方式:发送方发送数据包后,不等待接收方响应就立即接着发送下一个数据包。
使用此方式,Client或Server执行Socket连接、接收、发送操作时,Client或Server会中止工作,处于暂停状态。编程较简单,当对于需要网络操作比较繁重的时候并不太适合,此时需要采用异步方式。
1)对于Server的同步方式,在连接请求到来之前,ServerSocket一直处于Listen状态,而服务器则处于中止等待状态;当连接请求到来后,ServerSocket调用Accept方法,返回一个与ClientSocket相连的Socket处理此请求。直到请求完成后ServerSocket才继续监听等待。因为同步方式只使用一个线程来处理监听请求和响应请求。
SyncServerDemo
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace SyncServerDemo
{
class SyncServer
{
static void Main(string[] args)
{
Listening();
}
public static void Listening()
{
//设置缓冲区1024字节
byte[] buffer = new byte[10];
//初始化ServerSocket
IPHostEntry serverHost = Dns.GetHostEntry(Dns.GetHostName());
IPAddress serverIP = serverHost.AddressList[0];
IPEndPoint serverPort = new IPEndPoint(serverIP, 11010); //端口号按实际设置
Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//将ServerSocket绑定到本地
try
{
serverSocket.Bind(serverPort);
//开始监听,并设置最大连接队列为10
serverSocket.Listen(2);
while (true)
{
Console.WriteLine("Waiting for your connetion");
//此时Listenling线程将暂停等待,直到有连接请求的到来
Socket handler = serverSocket.Accept();
string receiveData = "";
Single dataTotalSize = 0;
int dataSize = handler.Receive(buffer);
receiveData += Encoding.ASCII.GetString(buffer, 0, dataSize);
dataTotalSize += dataSize;
//处理此请求
while (dataSize > 0 && handler.Available > 0)
{
dataSize = handler.Receive(buffer);
receiveData += Encoding.ASCII.GetString(buffer, 0, dataSize);
dataTotalSize += dataSize;
}
//显示接收到的请求数据
Console.WriteLine("Received data [size:{1} bytes] from [{2}]: \r\n {0}", receiveData, dataTotalSize, handler.RemoteEndPoint.ToString());
//将接收到的数据和数据大小返回给Client
byte[] returnBytes = Encoding.ASCII.GetBytes(receiveData + "\r\nDataSize: " + dataTotalSize);
handler.Send(returnBytes);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nHit any key to continue");
Console.Read();
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace SyncServerDemo
{
class SyncServer
{
static void Main(string[] args)
{
Listening();
}
public static void Listening()
{
//设置缓冲区1024字节
byte[] buffer = new byte[10];
//初始化ServerSocket
IPHostEntry serverHost = Dns.GetHostEntry(Dns.GetHostName());
IPAddress serverIP = serverHost.AddressList[0];
IPEndPoint serverPort = new IPEndPoint(serverIP, 11010); //端口号按实际设置
Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//将ServerSocket绑定到本地
try
{
serverSocket.Bind(serverPort);
//开始监听,并设置最大连接队列为10
serverSocket.Listen(2);
while (true)
{
Console.WriteLine("Waiting for your connetion");
//此时Listenling线程将暂停等待,直到有连接请求的到来
Socket handler = serverSocket.Accept();
string receiveData = "";
Single dataTotalSize = 0;
int dataSize = handler.Receive(buffer);
receiveData += Encoding.ASCII.GetString(buffer, 0, dataSize);
dataTotalSize += dataSize;
//处理此请求
while (dataSize > 0 && handler.Available > 0)
{
dataSize = handler.Receive(buffer);
receiveData += Encoding.ASCII.GetString(buffer, 0, dataSize);
dataTotalSize += dataSize;
}
//显示接收到的请求数据
Console.WriteLine("Received data [size:{1} bytes] from [{2}]: \r\n {0}", receiveData, dataTotalSize, handler.RemoteEndPoint.ToString());
//将接收到的数据和数据大小返回给Client
byte[] returnBytes = Encoding.ASCII.GetBytes(receiveData + "\r\nDataSize: " + dataTotalSize);
handler.Send(returnBytes);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nHit any key to continue");
Console.Read();
}
}
}
2)Client的同步方式,ClientSocket负责发出连接请求和请求数据,并接收返回的数据。同样是在单线程中处理请求和处理返回数据。
SyncClientDemo
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace SyncClientDemo
{
class SyncClient
{
static void Main(string[] args)
{
//SyncRequest("127.0.0.1", "Test");
//SyncRequest("fengmk2PC", "Test");
//Console.Read();
while (true)
{
Console.WriteLine("Enter any key except 'q' to Send message;");
Console.WriteLine("Enter 'q' to Exit;");
string requestdata = "";
requestdata = Console.ReadLine();
if (requestdata == "q")
break;
if (requestdata.Length > 0)
{
Console.WriteLine("Enter the HostName,");
string hostName = Console.ReadLine();
Console.WriteLine("Enter the Message Data.");
requestdata = Console.ReadLine();
SyncRequest(hostName, requestdata);
}
Console.WriteLine("");
}
}
public static void SyncRequest(string hostName, string requestData)
{
//设置缓冲区
byte[] buffer = new byte[1024];
//向Server发出连接请求
try
{
IPHostEntry serverHost = Dns.GetHostEntry(hostName);
IPEndPoint remoteEP = new IPEndPoint(serverHost.AddressList[0], 11010);
//初始化ClientSocket
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//发出请求连接
try
{
Console.WriteLine("ClientSocket connecting to [{0}:{1}]", serverHost.HostName, remoteEP.ToString());
clientSocket.Connect(remoteEP);
//连接成功
Console.WriteLine("Connect Success!");
byte[] msg = Encoding.ASCII.GetBytes(requestData);
//发送请求数据
clientSocket.Send(msg, msg.Length, SocketFlags.None);
Console.WriteLine("Send data: \r\n{0}", requestData);
//接收返回的响应数据
string receiveData = "";
int dataTotalSize = 0;
int dataSize = clientSocket.Receive(buffer, buffer.Length, SocketFlags.None);
receiveData += Encoding.ASCII.GetString(buffer, 0, dataSize);
dataTotalSize += dataSize;
while (dataSize > 0 && clientSocket.Available > 0)
{
dataSize = clientSocket.Receive(buffer, buffer.Length, SocketFlags.None);
receiveData += Encoding.ASCII.GetString(buffer, 0, dataSize);
dataTotalSize += dataSize;
}
//显示接收到的数据
Console.WriteLine("Received data [size:{1} bytes] from [{2}]: \r\n {0}", receiveData, dataTotalSize, clientSocket.RemoteEndPoint.ToString());
//释放ClientSocket
clientSocket.Shutdown(SocketShutdown.Both);
clientSocket.Close();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace SyncClientDemo
{
class SyncClient
{
static void Main(string[] args)
{
//SyncRequest("127.0.0.1", "Test");
//SyncRequest("fengmk2PC", "Test");
//Console.Read();
while (true)
{
Console.WriteLine("Enter any key except 'q' to Send message;");
Console.WriteLine("Enter 'q' to Exit;");
string requestdata = "";
requestdata = Console.ReadLine();
if (requestdata == "q")
break;
if (requestdata.Length > 0)
{
Console.WriteLine("Enter the HostName,");
string hostName = Console.ReadLine();
Console.WriteLine("Enter the Message Data.");
requestdata = Console.ReadLine();
SyncRequest(hostName, requestdata);
}
Console.WriteLine("");
}
}
public static void SyncRequest(string hostName, string requestData)
{
//设置缓冲区
byte[] buffer = new byte[1024];
//向Server发出连接请求
try
{
IPHostEntry serverHost = Dns.GetHostEntry(hostName);
IPEndPoint remoteEP = new IPEndPoint(serverHost.AddressList[0], 11010);
//初始化ClientSocket
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//发出请求连接
try
{
Console.WriteLine("ClientSocket connecting to [{0}:{1}]", serverHost.HostName, remoteEP.ToString());
clientSocket.Connect(remoteEP);
//连接成功
Console.WriteLine("Connect Success!");
byte[] msg = Encoding.ASCII.GetBytes(requestData);
//发送请求数据
clientSocket.Send(msg, msg.Length, SocketFlags.None);
Console.WriteLine("Send data: \r\n{0}", requestData);
//接收返回的响应数据
string receiveData = "";
int dataTotalSize = 0;
int dataSize = clientSocket.Receive(buffer, buffer.Length, SocketFlags.None);
receiveData += Encoding.ASCII.GetString(buffer, 0, dataSize);
dataTotalSize += dataSize;
while (dataSize > 0 && clientSocket.Available > 0)
{
dataSize = clientSocket.Receive(buffer, buffer.Length, SocketFlags.None);
receiveData += Encoding.ASCII.GetString(buffer, 0, dataSize);
dataTotalSize += dataSize;
}
//显示接收到的数据
Console.WriteLine("Received data [size:{1} bytes] from [{2}]: \r\n {0}", receiveData, dataTotalSize, clientSocket.RemoteEndPoint.ToString());
//释放ClientSocket
clientSocket.Shutdown(SocketShutdown.Both);
clientSocket.Close();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
}
测试如下:
(3)基于C/S架构的异步Socket示例
异步方式对应有:BeginAccept、EndAccept,BeginReceive、EndReceive,BeginSend、EndSend等方法。
异步方式:发送方发送一个数据包后,一直等到接收方响应后,才接着发送下一个数据包。
1)异步服务器端AsyncServer,异步Socket可在监听同时进行其他操作,如发送数据和读取数据。对于网络操作负荷比较大的程序来说特别适合。
对于异步ServerSocket,需要一个方法开始接受网络连接请求,一个回调方法AcceptCallback处理连接请求,一个回调方法ReceiveCallback处理接收数据,一个回调方法SendCallback处理发送数据。
AsyncServerDemo
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace AsyncServerDemo
{
class AsyncServer
{
static void Main(string[] args)
{
Listening();
}
//异步读取数据的辅助类
public class StateInfo
{
public Socket socket = null;
public const int bufferSize = 1024;
public byte[] buffer = new byte[bufferSize];
public StringBuilder sb = new StringBuilder();
}
public static ManualResetEvent EventManager = new ManualResetEvent(false);
public static void Listening()
{
//获得本地地址信息
IPHostEntry serverHost = Dns.GetHostEntry(Dns.GetHostName());
IPEndPoint serverEP = new IPEndPoint(serverHost.AddressList[0], 11010);
Console.WriteLine("Servar IP and Port is : {0}", serverEP.ToString());
//创建ServerSocket
Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
serverSocket.Bind(serverEP);
serverSocket.Listen(50);
while (true)
{
EventManager.Reset();
//异步监听
Console.WriteLine("Waiting for a connection");
serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), serverSocket);
//监听线程将阻塞,直到有连接请求到来
EventManager.WaitOne();
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
public static void AcceptCallback(IAsyncResult ar)
{
//唤醒监听线程
EventManager.Set();
//获得ClientSocke
Socket serverSocket = (Socket)ar.AsyncState;
Socket handler = serverSocket.EndAccept(ar);
//创建状态辅助对象
StateInfo state = new StateInfo();
state.socket = handler;
//读取请求数据
handler.BeginReceive(state.buffer, 0, state.buffer.Length, SocketFlags.None,
new AsyncCallback(ReceiveCallback), state);
}
public static void ReceiveCallback(IAsyncResult ar)
{
StateInfo state = (StateInfo)ar.AsyncState;
//读取数据
int dataSize = state.socket.EndReceive(ar);
if (dataSize > 0)
{
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, dataSize));
if (state.socket.Available > 0)
{
state.socket.BeginReceive(state.buffer, 0, state.buffer.Length, SocketFlags.None,
new AsyncCallback(ReceiveCallback), state);
}
else
{ //全部数据都接收完,则返回响应数据给Client
//显示接收数据
string content = state.sb.ToString();
Console.WriteLine("Receive data [{0} bytes] from [{1}] at {3}:\r\n{2}",
content.Length, state.socket.RemoteEndPoint.ToString(), content, DateTime.Now.ToLongTimeString());
//返回响应数据给Client
byte[] data = Encoding.ASCII.GetBytes(content + "\r\n Server have receive your data at " + DateTime.Now.ToLongTimeString());
state.socket.BeginSend(data, 0, data.Length, SocketFlags.None,
new AsyncCallback(SendCallback), state.socket);
}
}
}
public static void SendCallback(IAsyncResult ar)
{
try
{
Socket handler = (Socket)ar.AsyncState;
int sendSize = handler.EndSend(ar);
Console.WriteLine("Sent data [{0} bytes] to [{1}]", sendSize, handler.RemoteEndPoint.ToString());
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace AsyncServerDemo
{
class AsyncServer
{
static void Main(string[] args)
{
Listening();
}
//异步读取数据的辅助类
public class StateInfo
{
public Socket socket = null;
public const int bufferSize = 1024;
public byte[] buffer = new byte[bufferSize];
public StringBuilder sb = new StringBuilder();
}
public static ManualResetEvent EventManager = new ManualResetEvent(false);
public static void Listening()
{
//获得本地地址信息
IPHostEntry serverHost = Dns.GetHostEntry(Dns.GetHostName());
IPEndPoint serverEP = new IPEndPoint(serverHost.AddressList[0], 11010);
Console.WriteLine("Servar IP and Port is : {0}", serverEP.ToString());
//创建ServerSocket
Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
serverSocket.Bind(serverEP);
serverSocket.Listen(50);
while (true)
{
EventManager.Reset();
//异步监听
Console.WriteLine("Waiting for a connection");
serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), serverSocket);
//监听线程将阻塞,直到有连接请求到来
EventManager.WaitOne();
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
public static void AcceptCallback(IAsyncResult ar)
{
//唤醒监听线程
EventManager.Set();
//获得ClientSocke
Socket serverSocket = (Socket)ar.AsyncState;
Socket handler = serverSocket.EndAccept(ar);
//创建状态辅助对象
StateInfo state = new StateInfo();
state.socket = handler;
//读取请求数据
handler.BeginReceive(state.buffer, 0, state.buffer.Length, SocketFlags.None,
new AsyncCallback(ReceiveCallback), state);
}
public static void ReceiveCallback(IAsyncResult ar)
{
StateInfo state = (StateInfo)ar.AsyncState;
//读取数据
int dataSize = state.socket.EndReceive(ar);
if (dataSize > 0)
{
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, dataSize));
if (state.socket.Available > 0)
{
state.socket.BeginReceive(state.buffer, 0, state.buffer.Length, SocketFlags.None,
new AsyncCallback(ReceiveCallback), state);
}
else
{ //全部数据都接收完,则返回响应数据给Client
//显示接收数据
string content = state.sb.ToString();
Console.WriteLine("Receive data [{0} bytes] from [{1}] at {3}:\r\n{2}",
content.Length, state.socket.RemoteEndPoint.ToString(), content, DateTime.Now.ToLongTimeString());
//返回响应数据给Client
byte[] data = Encoding.ASCII.GetBytes(content + "\r\n Server have receive your data at " + DateTime.Now.ToLongTimeString());
state.socket.BeginSend(data, 0, data.Length, SocketFlags.None,
new AsyncCallback(SendCallback), state.socket);
}
}
}
public static void SendCallback(IAsyncResult ar)
{
try
{
Socket handler = (Socket)ar.AsyncState;
int sendSize = handler.EndSend(ar);
Console.WriteLine("Sent data [{0} bytes] to [{1}]", sendSize, handler.RemoteEndPoint.ToString());
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
}
使用之前编写的同步客户端SyncClient访问上面的异步服务器端AsyncServer,测试如下:
2)异步客户端AsyncClient
AsyncClientDemo
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace AsyncClientDemo
{
class AsyncClient
{
static void Main(string[] args)
{
AsyncRequest("fengmk2PC", "Test");
Console.Read();
}
//异步读取数据的辅助类
public class StateInfo
{
public Socket socket = null;
public const int bufferSize = 256;
public byte[] buffer = new byte[bufferSize];
public StringBuilder sb = new StringBuilder();
}
private static ManualResetEvent connectDone = new ManualResetEvent(false);
private static ManualResetEvent sendDone = new ManualResetEvent(false);
private static ManualResetEvent receiveDone = new ManualResetEvent(false);
public static void AsyncRequest(string hostName, string requestData)
{
try
{
IPHostEntry serverHost = Dns.GetHostEntry(hostName);
IPEndPoint remoteEP = new IPEndPoint(serverHost.AddressList[0], 11010);
//初始化ClientSocket
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//发出请求连接
clientSocket.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), clientSocket);
connectDone.WaitOne();
//发送数据到服务器端
Send(clientSocket, requestData);
sendDone.WaitOne();
//接收信息
Receive(clientSocket);
receiveDone.WaitOne();
clientSocket.Shutdown(SocketShutdown.Both);
clientSocket.Close();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
private static void ConnectCallback(IAsyncResult ar)
{
try
{
Socket handler = (Socket)ar.AsyncState;
handler.EndConnect(ar);
Console.WriteLine("Connected to {0}", handler.RemoteEndPoint.ToString());
//连接成功
connectDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
private static void Send(Socket socket, string data)
{
byte[] bytesData = Encoding.ASCII.GetBytes(data);
socket.BeginSend(bytesData, 0, bytesData.Length, SocketFlags.None,
new AsyncCallback(SendCallback), socket);
}
private static void SendCallback(IAsyncResult ar)
{
try
{
Socket handler = (Socket)ar.AsyncState;
int sendSize = handler.EndSend(ar);
Console.WriteLine("Sent data [{0} bytes] to [{1}]", sendSize, handler.RemoteEndPoint.ToString());
//已发送完毕
sendDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
private static void Receive(Socket socket)
{
try
{
StateInfo state = new StateInfo();
state.socket = socket;
socket.BeginReceive(state.buffer, 0, state.buffer.Length, SocketFlags.None,
new AsyncCallback(ReceiveCallback), state);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
private static void ReceiveCallback(IAsyncResult ar)
{
try
{
StateInfo state = (StateInfo)ar.AsyncState;
//读取数据
int dataSize = state.socket.EndReceive(ar);
if (dataSize > 0)
{
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, dataSize));
if (state.socket.Available > 0)
{
state.socket.BeginReceive(state.buffer, 0, state.buffer.Length, SocketFlags.None,
new AsyncCallback(ReceiveCallback), state);
}
else
{
//显示接收数据
string content = state.sb.ToString();
Console.WriteLine("Receive data [{0} bytes] from [{1}] at {3}:\r\n{2}",
content.Length, state.socket.RemoteEndPoint.ToString(), content, DateTime.Now.ToLongTimeString());
//接收完毕
receiveDone.Set();
}
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace AsyncClientDemo
{
class AsyncClient
{
static void Main(string[] args)
{
AsyncRequest("fengmk2PC", "Test");
Console.Read();
}
//异步读取数据的辅助类
public class StateInfo
{
public Socket socket = null;
public const int bufferSize = 256;
public byte[] buffer = new byte[bufferSize];
public StringBuilder sb = new StringBuilder();
}
private static ManualResetEvent connectDone = new ManualResetEvent(false);
private static ManualResetEvent sendDone = new ManualResetEvent(false);
private static ManualResetEvent receiveDone = new ManualResetEvent(false);
public static void AsyncRequest(string hostName, string requestData)
{
try
{
IPHostEntry serverHost = Dns.GetHostEntry(hostName);
IPEndPoint remoteEP = new IPEndPoint(serverHost.AddressList[0], 11010);
//初始化ClientSocket
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//发出请求连接
clientSocket.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), clientSocket);
connectDone.WaitOne();
//发送数据到服务器端
Send(clientSocket, requestData);
sendDone.WaitOne();
//接收信息
Receive(clientSocket);
receiveDone.WaitOne();
clientSocket.Shutdown(SocketShutdown.Both);
clientSocket.Close();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
private static void ConnectCallback(IAsyncResult ar)
{
try
{
Socket handler = (Socket)ar.AsyncState;
handler.EndConnect(ar);
Console.WriteLine("Connected to {0}", handler.RemoteEndPoint.ToString());
//连接成功
connectDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
private static void Send(Socket socket, string data)
{
byte[] bytesData = Encoding.ASCII.GetBytes(data);
socket.BeginSend(bytesData, 0, bytesData.Length, SocketFlags.None,
new AsyncCallback(SendCallback), socket);
}
private static void SendCallback(IAsyncResult ar)
{
try
{
Socket handler = (Socket)ar.AsyncState;
int sendSize = handler.EndSend(ar);
Console.WriteLine("Sent data [{0} bytes] to [{1}]", sendSize, handler.RemoteEndPoint.ToString());
//已发送完毕
sendDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
private static void Receive(Socket socket)
{
try
{
StateInfo state = new StateInfo();
state.socket = socket;
socket.BeginReceive(state.buffer, 0, state.buffer.Length, SocketFlags.None,
new AsyncCallback(ReceiveCallback), state);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
private static void ReceiveCallback(IAsyncResult ar)
{
try
{
StateInfo state = (StateInfo)ar.AsyncState;
//读取数据
int dataSize = state.socket.EndReceive(ar);
if (dataSize > 0)
{
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, dataSize));
if (state.socket.Available > 0)
{
state.socket.BeginReceive(state.buffer, 0, state.buffer.Length, SocketFlags.None,
new AsyncCallback(ReceiveCallback), state);
}
else
{
//显示接收数据
string content = state.sb.ToString();
Console.WriteLine("Receive data [{0} bytes] from [{1}] at {3}:\r\n{2}",
content.Length, state.socket.RemoteEndPoint.ToString(), content, DateTime.Now.ToLongTimeString());
//接收完毕
receiveDone.Set();
}
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
}
测试如下:
(4)总结:
只要明白Socket的工作原理,即三步骤,就可以轻松地利用Socket编写网络程序。