C# Socket编程 同步以及异步通信

摘要:
Socket通信方式:同步:客户端在发送请求之后必须等到服务器回应之后才可以发送下一条请求。而服务器端的套接字继续处于监听状态,继续接受其他客户端套接字请求。Socket构造函数:publicsocket。但需要注意的是套接字类型与协议类型并不是可以随便组合。EndAccept会返回新的socket对象。不能使用返回的这个socket接受队列中的任何附加连接。当需要原始线程继续执行时请在回调方法中使用ManualResetEvent的set方法BeginConnect回调方法中必须使用EndConnect()方法。

套接字简介:套接字最早是Unix的,window是借鉴过来的。TCP/IP协议族提供三种套接字:流式、数据报式、原始套接字。其中原始套接字允许对底层协议直接访问,一般用于检验新协议或者新设备问题,很少使用。

套接字编程原理:延续文件作用思想,打开-读写-关闭的模式。

C/S编程模式如下:

Ø服务器端:

打开通信通道,告诉本地机器,愿意在该通道上接受客户请求——监听,等待客户请求——接受请求,创建专用链接进行读写——处理完毕,关闭专用链接——关闭通信通道(当然其中监听到关闭专用链接可以重复循环)

Ø客户端:打开通信通道,连接服务器——数据交互——关闭信道。

Socket通信方式:

Ø同步:客户端在发送请求之后必须等到服务器回应之后才可以发送下一条请求。串行运行

Ø异步:客户端请求之后,不必等到服务器回应之后就可以发送下一条请求。并行运行

套接字模式:

Ø阻塞:执行此套接字调用时,所有调用函数只有在得到返回结果之后才会返回。在调用结果返回之前,当前进程会被挂起。即此套接字一直被阻塞在网络调用上。

Ø非阻塞:执行此套接字调用时,调用函数即使得不到得到返回结果也会返回。

套接字工作步骤:

Ø服务器监听:监听时服务器端套接字并不定位具体客户端套接字,而是处于等待链接的状态,实时监控网络状态

Ø客户端链接:客户端发出链接请求,要连接的目标是服务器端的套接字。为此客户端套接字必须描述服务器端套接字的服务器地址与端口号。

Ø链接确认:是指服务器端套接字监听到客户端套接字的链接请求时,它响应客户端链接请求,建立一个新的线程,把服务器端套接字的描述发送给客户端,一旦客户端确认此描述,则链接建立好。而服务器端的套接字继续处于监听状态,继续接受其他客户端套接字请求。

TCP/IP网络中,IP网络交互分类两大类:面向连接的交互与面向无连接的交互。

C# Socket编程 同步以及异步通信第1张C# Socket编程 同步以及异步通信第2张

Socket构造函数:public socket(AddressFamily寻址类型, SocketType套接字类型, ProtocolType协议类型)。但需要注意的是套接字类型与协议类型并不是可以随便组合。

SocketType

ProtocolType

描述

Stream

Tcp

面向连接

Dgram

Udp

面向无连接

Raw

Icmp

网际消息控制

Raw

Raw

基础传输协议

Socket类的公共属性:

属性名

描述

AddressFamily

获取Socket的地址族

Available

获取已经从网络接收且可供读取的数据量

Blocking

获取或设置一个值,只是socket是否处于阻塞模式

Connected

获取一个值,指示当前连接状态

Handle

获取socket的操作系统句柄

LocalEndPoint

获取本地终端EndPoint

RemoteEndPoint

获取远程终端EndPoint

ProtocolType

获取协议类型

SocketType

获取SocketType类型

Socket常用方法:

Bind(EndPoint)

服务器端套接字需要绑定到特定的终端,客户端也可以先绑定再请求连接

Listen(int)

监听端口,其中parameters表示最大监听数

Accept()

接受客户端链接,并返回一个新的链接,用于处理同客户端的通信问题

Send()

发送数据

Send(byte[])

简单发送数据

Send(byte[],SocketFlag)

使用指定的SocketFlag发送数据

Send(byte[], int, SocketFlag)

使用指定的SocketFlag发送指定长度数据

Send(byte[], int, int, SocketFlag)

使用指定的SocketFlag,将指定字节数的数据发送到已连接的socket(从指定偏移量开始)

Receive()

接受数据

Receive(byte[])

简单接受数据

Receive (byte[],SocketFlag)

使用指定的SocketFlag接受数据

Receive (byte[], int, SocketFlag)

使用指定的SocketFlag接受指定长度数据

Receive (byte[], int, int, SocketFlag)

使用指定的SocketFlag,从绑定的套接字接收指定字节数的数据,并存到指定偏移量位置的缓冲区

Connect(EndPoint)

连接远程服务器

ShutDown(SocketShutDown)

禁用套接字,其中SocketShutDown为枚举,Send禁止发送,Receive为禁止接受,Both为两者都禁止

Close()

关闭套接字,释放资源

异步通信方法:

BeginAccept(AsynscCallBack,object)

开始一个一步操作接受一个连接尝试。参数:一个委托。一个对象。对象包含此请求的状态信息。其中回调方法中必须使用EndAccept方法。应用程序调用BegineAccept方法后,系统会使用单独的线程执行指定的回调方法并在EndAccept上一直处于阻塞状态,直至监测到挂起的链接。EndAccept会返回新的socket对象。供你来同远程主机数据交互。不能使用返回的这个socket接受队列中的任何附加连接。调用BeginAccept当希望原始线程阻塞的时候,请调用WaitHandle.WaitOne方法。当需要原始线程继续执行时请在回调方法中使用ManualResetEvent的set方法

BeginConnect(EndPoint, AsyncCallBack, Object)

回调方法中必须使用EndConnect()方法。Object中存储了连接的详细信息。

BeginSend(byte[], SocketFlag, AsyncCallBack, Object)

BegineReceive(byte[], SocketFlag, AsyncCallBack, Object)

BegineDisconnect(bool, AsyncCallBack, Object)

给出同步通信与异步通信的示例:

同步通信:

预定义结构体,同步通信没有多线程异步委托回调,所以无需预定义结构体

客户端Client

classProgram

{

staticvoidMain()

{

try{

intport = 2000;

stringhost ="127.0.0.1";

IPAddressip =IPAddress.Parse(host);

IPEndPointipe =newIPEndPoint(ip, port);//把ip和端口转化为IPEndPoint实例

Socketc =newSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);//创建一个Socket

Console.WriteLine("Conneting...");

c.Connect(ipe);//连接到服务器

stringsendStr ="hello!This is a socket test";

byte[] bs =Encoding.ASCII.GetBytes(sendStr);

Console.WriteLine("Send Message");

c.Send(bs, bs.Length, 0);//发送测试信息

stringrecvStr ="";

byte[] recvBytes =newbyte[1024];

intbytes;

bytes = c.Receive(recvBytes, recvBytes.Length, 0);//从服务器端接受返回信息

recvStr +=Encoding.ASCII.GetString(recvBytes, 0, bytes);

Console.WriteLine("Client Get Message:{0}", recvStr);//显示服务器返回信息

c.Close();

}

catch(ArgumentNullExceptione){

Console.WriteLine("ArgumentNullException: {0}", e);

}

catch(SocketExceptione){

Console.WriteLine("SocketException: {0}", e);

}

Console.WriteLine("Press Enter to Exit");

Console.ReadLine();

}

}

服务器端:

classProgram

{

staticvoidMain()

{

try{

intport = 2000;

stringhost ="127.0.0.1";

IPAddressip =IPAddress.Parse(host);

IPEndPointipe =newIPEndPoint(ip, port);

Sockets =newSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);//创建一个Socket类

s.Bind(ipe);//绑定2000端口

s.Listen(0);//开始监听

Console.WriteLine("Wait for connect");

Sockettemp = s.Accept();//为新建连接创建新的Socket。

Console.WriteLine("Get a connect");

stringrecvStr ="";

byte[] recvBytes =newbyte[1024];

intbytes;

bytes = temp.Receive(recvBytes, recvBytes.Length, 0);//从客户端接受信息

recvStr +=Encoding.ASCII.GetString(recvBytes, 0, bytes);

Console.WriteLine("Server Get Message:{0}", recvStr);//把客户端传来的信息显示出来

stringsendStr ="Ok!Client Send Message Sucessful!";

byte[] bs =Encoding.ASCII.GetBytes(sendStr);

temp.Send(bs, bs.Length, 0);//返回客户端成功信息

temp.Close();

s.Close();

}

catch(ArgumentNullExceptione){

Console.WriteLine("ArgumentNullException: {0}", e);}

catch(SocketExceptione){

Console.WriteLine("SocketException: {0}", e);}

Console.WriteLine("Press Enter to Exit");

Console.ReadLine();

}

}

异步通信:

客户端Client:

预定义结构体,用于异步委托之间的传递。用户根据自己需要定制即可

publicclassStateObject

{

// Client socket.

publicSocketworkSocket =null;

// Size of receive buffer.

publicconstintBufferSize = 256;

// Receive buffer.

publicbyte[] buffer =newbyte[BufferSize];

// Received data string.

publicStringBuildersb =newStringBuilder();

}

正文:

publicclassAsynchronousClient

{

// The port number for the remote device.

privateconstintport = 11000;

// ManualResetEvent instances signal completion.

privatestaticManualResetEventconnectDone =newManualResetEvent(false);

privatestaticManualResetEventsendDone =newManualResetEvent(false);

privatestaticManualResetEventreceiveDone =newManualResetEvent(false);

// The response from the remote device.

privatestaticStringresponse =String.Empty;

privatestaticvoidStartClient(){

// Connect to a remote device.

try{

// Establish the remote endpoint for the socket.

// The name of the remote device is "host.contoso.com".

IPHostEntryipHostInfo =Dns.Resolve("host.contoso.com");

IPAddressipAddress = ipHostInfo.AddressList[0];

IPEndPointremoteEP =newIPEndPoint(ipAddress, port);

// Create a TCP/IP socket.

Socketclient =newSocket(AddressFamily.InterNetwork,

SocketType.Stream,ProtocolType.Tcp);

// Connect to the remote endpoint.

client.BeginConnect(remoteEP,

newAsyncCallback(ConnectCallback),client);

connectDone.WaitOne();

// Send test data to the remote device.

Send(client,"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(Exceptione){

Console.WriteLine(e.ToString());}

}

privatestaticvoidConnectCallback(IAsyncResultar)

{

try{

// Retrieve the socket from the state object.

Socketclient = (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(Exceptione){

Console.WriteLine(e.ToString());}

}

privatestaticvoidReceive(Socketclient)

{

try{

// Create the state object.

StateObjectstate =newStateObject();

state.workSocket = client;

// Begin receiving the data from the remote device.

client.BeginReceive(state.buffer, 0,StateObject.BufferSize, 0,

newAsyncCallback(ReceiveCallback), state);

}

catch(Exceptione){

Console.WriteLine(e.ToString());}

}

privatestaticvoidReceiveCallback(IAsyncResultar)

{

try{

// Retrieve the state object and the client socket

// from the asynchronous state object.

StateObjectstate = (StateObject)ar.AsyncState;

Socketclient = state.workSocket;

// Read data from the remote device.

intbytesRead = 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,

newAsyncCallback(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(Exceptione){

Console.WriteLine(e.ToString());}

}

privatestaticvoidSend(Socketclient,Stringdata)

{

// 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,

newAsyncCallback(SendCallback), client);

}

privatestaticvoidSendCallback(IAsyncResultar)

{

try{

// Retrieve the socket from the state object.

Socketclient = (Socket)ar.AsyncState;

// Complete sending the data to the remote device.

intbytesSent = client.EndSend(ar);

Console.WriteLine("Sent {0} bytes to server.", bytesSent);

// Signal that all bytes have been sent.

sendDone.Set();

}

catch(Exceptione){

Console.WriteLine(e.ToString());}

}

publicstaticintMain(String[] args)

{

StartClient();

return0;

}

}

服务器端Server:

预定义结构体,用于异步委托之间的传递。同客户端的一致。不再赘述

正文:

// State object for reading client data asynchronously

publicclassAsynchronousSocketListener

{

// Thread signal.

publicstaticManualResetEventallDone =newManualResetEvent(false);

publicAsynchronousSocketListener(){}

publicstaticvoidStartListening()

{

// Data buffer for incoming data.

byte[] bytes =newByte[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(Dns.GetHostName());

IPHostEntryipHostInfo =Dns.Resolve("127.0.0.1");

IPAddressipAddress = ipHostInfo.AddressList[0];

IPEndPointlocalEndPoint =newIPEndPoint(ipAddress, 11000);

// Create a TCP/IP socket.

Socketlistener =newSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);

// Bind the socket to the local endpoint and listen for incoming connections.

try{

listener.Bind(localEndPoint);

listener.Listen(100);

while(true){

// Set the event to nonsignaled state.

allDone.Reset();

// Start an asynchronous socket to listen for connections.

Console.WriteLine("Waiting for a connection...");

listener.BeginAccept(newAsyncCallback(AcceptCallback),listener);

// Wait until a connection is made before continuing.

allDone.WaitOne();

}

}

catch(Exceptione){

Console.WriteLine(e.ToString());}

Console.WriteLine(" Press ENTER to continue...");

Console.Read();

}

publicstaticvoidAcceptCallback(IAsyncResultar)

{

// Signal the main thread to continue.

allDone.Set();

// Get the socket that handles the client request.

Socketlistener = (Socket)ar.AsyncState;

Sockethandler = listener.EndAccept(ar);

// Create the state object.

StateObjectstate =newStateObject();

state.workSocket = handler;

handler.BeginReceive(state.buffer, 0,StateObject.BufferSize, 0,newAsyncCallback(ReadCallback), state);

}

publicstaticvoidReadCallback(IAsyncResultar)

{

Stringcontent =String.Empty;

// Retrieve the state object and the handler socket

// from the asynchronous state object.

StateObjectstate = (StateObject)ar.AsyncState;

Sockethandler = state.workSocket;

// Read data from the client socket.

intbytesRead = handler.EndReceive(ar);

if(bytesRead > 0)

{

// Theremight 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. Data : {1}",

content.Length, content);

// Echo the data back to the client.

Send(handler,"Server return :"+ content);

}

else{

// Not all data received. Get more.

handler.BeginReceive(state.buffer, 0,StateObject.BufferSize, 0,

newAsyncCallback(ReadCallback), state);

}

}

}

privatestaticvoidSend(Sockethandler,Stringdata){

// 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,

newAsyncCallback(SendCallback), handler);

}

privatestaticvoidSendCallback(IAsyncResultar)

{

try{

// Retrieve the socket from the state object.

Sockethandler = (Socket)ar.AsyncState;

// Complete sending the data to the remote device.

intbytesSent = handler.EndSend(ar);

Console.WriteLine("Sent {0} bytes to client.", bytesSent);

handler.Shutdown(SocketShutdown.Both);

handler.Close();

}

catch(Exceptione){

Console.WriteLine(e.ToString());

}

}

publicstaticintMain(String[] args)

{

StartListening();

return0;

}

}

免责声明:文章转载自《C# Socket编程 同步以及异步通信》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Oracle的thin驱动和oci驱动有什么不同?哪个性能好些?thinkphp过滤xss下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

地址族与数据序列 (转)

地址族与数据序列 分配给套接字的IP地址与端口号 IP是网络协议的简写,为收发网络数据而分配给计算机的值。端口号是为区分程序中创建的套接字而分配给套接字的序号。 网络地址 两种IP地址: IPv4和IPv6的主要差别是表示IP地址所用的字节数。 IPv4标准的4字节IP地址分为网络地址和主机地址。且分为ABCD等类型。 网络地址(网络ID)是为区...

xe 最大连接数限制、记录客户连接、心跳

xe 最大连接数限制、记录客户连接、心跳 //author: cxg unit DSServerContainer; interface usesSysUtils, Classes, IniFiles, Windows, Provider, DBClient,DSTCPServerTransport,DSServer, DSCommonServer, DB...

PHP socket 接收 java端口 netty 网络字节序

java 服务端测试代码: @Override public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throwsException { buffer.writeShort(5); buffer.writeI...

C#实现异步阻塞TCP(SocketAsyncEventArgs,SendAsync,ReceiveAsync,AcceptAsync,ConnectAsync)

1.类 (1)socket IO操作内存管理类 BufferManager // This class creates a single large buffer which can be divided up // and assigned to SocketAsyncEventArgs objects for use with ea...

Connection reset by peer的常见原因

 Connection reset by peer的常见原因: 1)服务器的并发连接数超过了其承载量,服务器会将其中一些连接关闭;    如果知道实际连接服务器的并发客户数没有超过服务器的承载量,看下有没有网络流量异常。可以使用netstat -an查看网络连接情况。 2)客户端关掉了socket,而服务器还在给客户端发送数据;  这属于正常情况 3)...

Windows phone 8 学习笔记(3) 通信(转)

Windows phone 8 可利用的数据通信方式比较广泛,在硬件支持的前提下,我们可以利用WiFi、蓝牙、临近感应等多种方式。数据交互一般通过套接字来完成,我们将在本文详细的分析。 快速导航:一、WP8套接字二、蓝牙三、NFC四、获取网络状态五、访问web的几种方式 一、WP8套接字 1)创建套接字客户端 Windows phone 8中的套接字并...