C#socket资料汇总
来源:互联网 发布:淘宝抢购秒杀器下载 编辑:程序博客网 时间:2024/05/16 09:07
最近需要socket 类的编程,就找了一些资料:
一 最简单的:
首先从原理上解释一下采用Socket接口的网络通讯,这里以最常用的C/S模式作为范例,首先,服务端有一个进程(或多个进程)在指定的端口等待客户来连接,服务程序等待客户的连接信息,一旦连接上之后,就可以按设计的数据交换方法和格式进行数据传输。客户端在需要的时刻发出向服务端的连接请求。这里为了便于理解,提到了一些调用及其大致的功能。使用socket调用后,仅产生了一个可以使用的socket描述符,这时还不能进行通信,还要使用其他的调用,以使得socket所指的结构中使用的信息被填写完。
在使用TCP协议时,一般服务端进程先使用socket调用得到一个描述符,然后使用bind调用将一个名字与socket描述符连接起来,对于Internet域就是将Internet地址联编到socket。之后,服务端使用listen调用指出等待服务请求队列的长度。然后就可以使用accept调用等待客户端发起连接,一般是阻塞等待连接,一旦有客户端发出连接,accept返回客户的地址信息,并返回一个新的socket描述符,该描述符与原先的socket有相同的特性,这时服务端就可以使用这个新的socket进行读写操作了。一般服务端可能在accept返回后创建一个新的进程进行与客户的通信,父进程则再到accept调用处等待另一个连接。客户端进程一般先使用socket调用得到一个socket描述符,然后使用connect向指定的服务器上的指定端口发起连接,一旦连接成功返回,就说明已经建立了与服务器的连接,这时就可以通过socket描述符进行读写操作了。
.NetFrameWork为Socket通讯提供了System.Net.Socket命名空间,在这个命名空间里面有以下几个常用的重要类分别是:
·Socket类这个低层的类用于管理连接,WebRequest,TcpClient和UdpClient在内部使用这个类。
·NetworkStream类这个类是从Stream派生出来的,它表示来自网络的数据流
·TcpClient类允许创建和使用TCP连接
·TcpListener类允许监听传入的TCP连接请求
·UdpClient类用于UDP客户创建连接(UDP是另外一种TCP协议,但没有得到广泛的使用,主要用于本地网络)
下面我们来看一个基于Socket的双机通信代码的C#版本
首先创建Socket对象的实例,这可以通过Socket类的构造方法来实现:
publicSocket(AddressFamilyaddressFamily,SocketTypesocketType,ProtocolTypeprotocolType);
其中,addressFamily参数指定Socket使用的寻址方案,socketType参数指定Socket的类型,protocolType参数指定Socket使用的协议。
下面的示例语句创建一个Socket,它可用于在基于TCP/IP的网络(如Internet)上通讯。
Sockettemp=newSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
若要使用UDP而不是TCP,需要更改协议类型,如下面的示例所示:
Sockettemp=newSocket(AddressFamily.InterNetwork,SocketType.Dgram,ProtocolType.Udp);
一旦创建Socket,在客户端,你将可以通过Connect方法连接到指定的服务器(你可以在Connect方法前Bind端口,就是以指定的端口发起连接,如果不事先Bind端口号的话,系统会默认在1024到5000随机绑定一个端口号),并通过Send方法向远程服务器发送数据,而后可以通过Receive从服务端接收数据;而在服务器端,你需要使用Bind方法绑定所指定的接口使Socket与一个本地终结点相联,并通过Listen方法侦听该接口上的请求,当侦听到用户端的连接时,调用Accept完成连接的操作,创建新的Socket以处理传入的连接请求。使用完Socket后,使用Close方法关闭Socket。
可以看出,以上许多方法包含EndPoint类型的参数,在Internet中,TCP/IP使用一个网络地址和一个服务端口号来唯一标识设备。网络地址标识网络上的特定设备;端口号标识要连接到的该设备上的特定服务。网络地址和服务端口的组合称为终结点,在.NET框架中正是由EndPoint类表示这个终结点,它提供表示网络资源或服务的抽象,用以标志网络地址等信息。.Net同时也为每个受支持的地址族定义了EndPoint的子代;对于IP地址族,该类为IPEndPoint。IPEndPoint 类包含应用程序连接到主机上的服务所需的主机和端口信息,通过组合服务的主机IP地址和端口号,IPEndPoint类形成到服务的连接点。
用到IPEndPoint类的时候就不可避免地涉及到计算机IP地址,System.Net命名空间中有两种类可以得到IP地址实例:
·IPAddress类:IPAddress类包含计算机在IP网络上的地址。其Parse方法可将IP地址字符串转换为IPAddress实例。下面的语句创建一个IPAddress实例:
IPAddressmyIP=IPAddress.Parse(
"192.168.0.1"
);
需要知道的是:Socket类支持两种基本模式:同步和异步。其区别在于:在同步模式中,按块传输,对执行网络操作的函数(如Send和 Receive)的调用一直等到所有内容传送操作完成后才将控制返回给调用程序。在异步模式中,是按位传输,需要指定发送的开始和结束。同步模式是最常用的模式,我们这里的例子也是使用同步模式。
下面看一个完整的例子,client向server发送一段测试字符串,server接收并显示出来,给予client成功响应。
//client端
usingSystem;
usingSystem.Text;
usingSystem.IO;
usingSystem.Net;
usingSystem.Net.Sockets;
namespacesocketsample
{
classClass1
{
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!Thisisasockettest"
;
byte
[]bs=Encoding.ASCII.GetBytes(sendStr);
Console.WriteLine(
"SendMessage"
);
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(
"ClientGetMessage:{0}"
,recvStr);
//显示服务器返回信息
c.Close();
}
catch
(ArgumentNullExceptione)
{
Console.WriteLine(
"ArgumentNullException:{0}"
,e);
}
catch
(SocketExceptione)
{
Console.WriteLine(
"SocketException:{0}"
,e);
}
Console.WriteLine(
"PressEntertoExit"
);
Console.ReadLine();
}
}
}
//server端
usingSystem;
usingSystem.Text;
usingSystem.IO;
usingSystem.Net;
usingSystem.Net.Sockets;
namespaceProject1
{
classClass2
{
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(
"Waitforconnect"
);
Sockettemp=s.Accept();
//为新建连接创建新的Socket。
Console.WriteLine(
"Getaconnect"
);
stringrecvStr=
""
;
byte
[]recvBytes=newbyte[1024];
intbytes;
bytes=temp.Receive(recvBytes,recvBytes.Length,0);
//从客户端接受信息
recvStr+=Encoding.ASCII.GetString(recvBytes,0,bytes);
Console.WriteLine(
"ServerGetMessage:{0}"
,recvStr);
//把客户端传来的信息显示出来
stringsendStr=
"Ok!ClientSendMessageSucessful!"
;
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(
"PressEntertoExit"
);
Console.ReadLine();
}
}
}
上面的例子是用的Socket类,System.Net.Socket命名空间还提供了两个抽象高级类TCPClient和UDPClient和用于通讯流处理的NetWorkStream,让我们看下例子
这个可能简单了点,异步的可以看下面的例子:
http://kb.cnblogs.com/a/2098632/
写在最前:以前在C\C++控制台,简单MFC和C#程序里简单接触了网络套接字编程。了解了网络套接字是这样一个流程 打开 -> 发送/接收->关闭 的简单过程。由于网络传输速度影响,在网络套接字的同步调用时会对程序的使用性产生影响(程序界面被卡死),后来知道可以使用异步编程的概念——通过开线程来达到不阻塞用户界面的效果。后来在接触网络套接字编程的次数多了以后,在C#.NET环境中发现Socket竟然多出了两类方法 XXXXAsync 和 BeginXXXX / EndXXXX。接下来就用代码演示一下这两类方法如何使用~
接下来的页面会很长,能扯一点的现在这扯一点。这两类方法分别对应SocketAsyncEventArgs 、 IAsyncResult。我暂时也讲不出什么,有问题问吧还是。文章最后有如何在vs一个解决方案中调试启动多个项目(这可能是很多人没有注意到的操作)。
So long,Coding
首先是XXXXAsync的,
Server
01
using
System;
02
using
System.Collections.Generic;
03
using
System.Text;
04
using
System.Net.Sockets;
05
using
System.Net;
06
07
namespace
SocketTest
08
{
09
class
Program
10
{
11
static
void
Main(
string
[] args)
12
{
13
Socket serverSk =
new
Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
14
15
serverSk.Bind(
new
IPEndPoint(IPAddress.Parse(
"127.0.0.1"
), 8596));
16
serverSk.Listen(1);
17
18
SocketAsyncEventArgs AcceptSAE =
new
SocketAsyncEventArgs();
19
AcceptSAE.Completed +=
new
EventHandler<socketasynceventargs>(AcceptSAE_Completed);
20
serverSk.AcceptAsync(AcceptSAE);
21
22
Console.ReadLine();
23
}
24
25
static
void
AcceptSAE_Completed(
object
sender, SocketAsyncEventArgs e)
26
{
27
Socket serverSk = sender
as
Socket;
28
if
(e.SocketError == SocketError.Success)
29
{
30
serverSk = e.AcceptSocket;
31
SocketAsyncEventArgs SendSAE =
new
SocketAsyncEventArgs();
32
byte
[] data = System.Text.Encoding.UTF8.GetBytes(
"OK,Just Put IT!"
);
33
SendSAE.SetBuffer(data, 0, data.Length);
34
SendSAE.Completed +=
new
EventHandler<socketasynceventargs>(SendSAE_Completed);
35
36
SocketAsyncEventArgs RecieveSAE =
new
SocketAsyncEventArgs();
37
byte
[] buffer =
new
byte
[2048];
//因为我们不知道上面的字符串究竟会场生多少字节,这里我们就设置一个理论上可以满足大小的值2046。
38
RecieveSAE.SetBuffer(buffer, 0, buffer.Length);
39
RecieveSAE.Completed +=
new
EventHandler<socketasynceventargs>(RecieveSAE_Completed);
40
41
serverSk.ReceiveAsync(RecieveSAE);
42
serverSk.SendAsync(SendSAE);
43
}
44
else
45
Console.WriteLine(
"接受网络套接字连接请求失败!具体原因请自己调试!"
);
46
}
47
48
49
static
void
RecieveSAE_Completed(
object
sender, SocketAsyncEventArgs e)
50
{
51
Socket sk = sender
as
Socket;
52
byte
[] data = e.Buffer;
//注意这里,如何取关联到套接字的发送接受的缓冲区中的值。
53
string
msg = System.Text.Encoding.UTF8.GetString(data);
54
Console.WriteLine(
"Message received: "
+ msg);
55
56
// sk.DisconnectAsync();//你看看 该怎么做呢?
57
}
58
59
static
void
SendSAE_Completed(
object
sender, SocketAsyncEventArgs e)
60
{
61
Socket sk = sender
as
Socket;
62
if
(e.SocketError == SocketError.Success)
63
{
64
Console.WriteLine(
"Send complete!"
);
65
66
67
byte
[] data = e.Buffer;
//注意这里,如何取关联到套接字的发送接受的缓冲区中的值。
68
string
msg = System.Text.Encoding.UTF8.GetString(data);
69
Console.WriteLine(
"What you sent: "
+ msg);
70
}
71
}
72
}
73
}</socketasynceventargs></socketasynceventargs></socketasynceventargs>
Client:
01
using
System;
02
using
System.Collections.Generic;
03
using
System.Text;
04
using
System.Net.Sockets;
05
using
System.Net;
06
07
namespace
SocketTestTwo
08
{
09
class
Program
10
{
11
static
void
Main(
string
[] args)
12
{
13
Socket clientSk =
new
Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
14
15
SocketAsyncEventArgs ConnectSAE =
new
SocketAsyncEventArgs();
16
ConnectSAE.RemoteEndPoint =
new
IPEndPoint(IPAddress.Parse(
"127.0.0.1"
), 8596);
17
ConnectSAE.Completed +=
new
EventHandler<socketasynceventargs>(ConnectSAE_Completed);
18
clientSk.ConnectAsync(ConnectSAE);
19
Console.ReadLine();
20
}
21
22
static
void
ConnectSAE_Completed(
object
sender, SocketAsyncEventArgs e)
23
{
24
Socket clientSk = sender
as
Socket;
25
if
(e.SocketError == SocketError.Success && clientSk.Connected)
26
{
27
SocketAsyncEventArgs SendSAE =
new
SocketAsyncEventArgs();
28
byte
[] data = System.Text.Encoding.UTF8.GetBytes(
"I want put all funy things together!"
);
29
SendSAE.SetBuffer(data, 0, data.Length);
30
SendSAE.Completed +=
new
EventHandler<socketasynceventargs>(SendSAE_Completed);
31
32
SocketAsyncEventArgs RecieveSAE =
new
SocketAsyncEventArgs();
33
byte
[] buffer =
new
byte
[2048];
//因为我们不知道上面的字符串究竟会场生多少字节,这里我们就设置一个理论上可以满足大小的值2046。
34
RecieveSAE.SetBuffer(buffer, 0, buffer.Length);
35
RecieveSAE.Completed +=
new
EventHandler<socketasynceventargs>(RecieveSAE_Completed);
36
37
//先调用异步接收,再调用异步发送。让你体验到异步明显非一般的感觉。
38
clientSk.ReceiveAsync(RecieveSAE);
39
clientSk.SendAsync(SendSAE);
40
}
41
}
42
43
static
void
RecieveSAE_Completed(
object
sender, SocketAsyncEventArgs e)
44
{
45
Socket sk = sender
as
Socket;
46
byte
[] data = e.Buffer;
//注意这里,如何取关联到套接字的发送接受的缓冲区中的值。
47
string
msg = System.Text.Encoding.UTF8.GetString(data);
48
Console.WriteLine(
"Message received: "
+msg);
49
50
//sk.DisconnectAsync();//你看看 该怎么做呢?
51
}
52
53
static
void
SendSAE_Completed(
object
sender, SocketAsyncEventArgs e)
54
{
55
Socket sk = sender
as
Socket;
56
if
(e.SocketError == SocketError.Success)
57
{
58
Console.WriteLine(
"Send complete!"
);
59
}
60
}
61
62
63
}
64
}</socketasynceventargs></socketasynceventargs></socketasynceventargs>
1
<socketasynceventargs><socketasynceventargs><socketasynceventargs><img src=
"http://pic002.cnblogs.com/images/2011/79702/2011070520394016.jpg"
><br></socketasynceventargs></socketasynceventargs></socketasynceventargs>
然后是BenginXXXX 和 EndXXXX的
Server
001
using
System;
002
using
System.Collections.Generic;
003
using
System.Text;
004
using
System.Net.Sockets;
005
using
System.Net;
006
007
namespace
SocketTestt
008
{
009
public
class
MyObject
010
{
011
#region 类字段
012
013
private
Socket _Socket;
014
private
string
_MyName =
""
;
015
private
byte
[] _Buffer;
016
017
018
#endregion
019
020
#region 类属性
021
022
public
Socket Socket
023
{
024
get
{
return
_Socket; }
025
set
{ _Socket = value; }
026
}
027
028
029
public
byte
[] Buffer
030
{
031
get
{
return
_Buffer; }
032
set
{ _Buffer = value; }
033
}
034
035
036
public
string
MyName
037
{
038
get
{
return
_MyName; }
039
set
{ _MyName = value; }
040
}
041
042
#endregion
043
044
#region 构造函数
045
046
public
MyObject(Socket socket,
string
myName)
047
{
048
_Socket = socket;
049
_MyName = myName;
050
}
051
public
MyObject(Socket socket,
string
myName,
byte
[] buffer)
052
{
053
_Socket = socket;
054
_MyName = myName;
055
_Buffer = buffer;
056
}
057
058
#endregion
059
}
060
061
class
Program
062
{
063
static
void
Main(
string
[] args)
064
{
065
Socket server =
new
Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
066
067
server.Bind(
new
IPEndPoint(IPAddress.Parse(
"127.0.0.1"
), 8596));
068
server.Listen(1);
069
070
server.BeginAccept(
new
AsyncCallback(AcceptComplete),
new
MyObject(server,
"开始连接了"
));
071
072
Console.ReadLine();
073
074
}
075
076
077
static
void
AcceptComplete(IAsyncResult ar)
078
{
079
MyObject myObj = ar.AsyncState
as
MyObject;
080
Socket serverSk = myObj.Socket.EndAccept(ar);
081
082
byte
[] buffer =
new
byte
[2048];
//虽然不知道会收到多少,但是多了总比少了好。
083
084
serverSk.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None,
new
AsyncCallback(RecievedComplete),
new
MyObject(serverSk,
"开始接收了"
, buffer));
085
086
byte
[] datas = System.Text.Encoding.UTF8.GetBytes(
"I know , Just put it!"
);
087
serverSk.BeginSend(datas, 0, datas.Length, SocketFlags.None,
new
AsyncCallback(SendComplete),
new
MyObject(serverSk,
"开始发送了"
, datas));
088
089
}
090
091
static
void
SendComplete(IAsyncResult ar)
092
{
093
MyObject myObj = ar.AsyncState
as
MyObject;
094
Socket sk = myObj.Socket;
095
096
int
sended = sk.EndSend(ar);
097
098
Console.WriteLine(System.Text.Encoding.UTF8.GetString(myObj.Buffer));
099
}
100
101
static
void
RecievedComplete(IAsyncResult ar)
102
{
103
104
MyObject myObj = ar.AsyncState
as
MyObject;
105
Socket sk = myObj.Socket;
106
107
int
recieved = sk.EndReceive(ar);
108
109
Console.WriteLine(System.Text.Encoding.UTF8.GetString(myObj.Buffer));
110
}
111
}
112
}
Client
001
using
System;
002
using
System.Collections.Generic;
003
using
System.Text;
004
using
System.Net.Sockets;
005
using
System.Net;
006
007
namespace
SocketTwo
008
{
009
public
class
MyObject
010
{
011
#region 类字段
012
013
private
Socket _Socket;
014
private
string
_MyName =
""
;
015
private
byte
[] _Buffer;
016
017
018
#endregion
019
020
#region 类属性
021
022
public
Socket Socket
023
{
024
get
{
return
_Socket; }
025
set
{ _Socket = value; }
026
}
027
028
029
public
byte
[] Buffer
030
{
031
get
{
return
_Buffer; }
032
set
{ _Buffer = value; }
033
}
034
035
036
public
string
MyName
037
{
038
get
{
return
_MyName; }
039
set
{ _MyName = value; }
040
}
041
042
#endregion
043
044
#region 构造函数
045
046
public
MyObject(Socket socket,
string
myName)
047
{
048
_Socket = socket;
049
_MyName = myName;
050
}
051
public
MyObject(Socket socket,
string
myName,
byte
[] buffer)
052
{
053
_Socket = socket;
054
_MyName = myName;
055
_Buffer = buffer;
056
}
057
058
#endregion
059
}
060
061
class
Program
062
{
063
static
void
Main(
string
[] args)
064
{
065
Socket clientSk =
new
Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
066
067
clientSk.BeginConnect(
new
IPEndPoint(IPAddress.Parse(
"127.0.0.1"
), 8596),
new
AsyncCallback(ConnectComplete),
new
MyObject(clientSk,
"开始连接了"
));
068
069
Console.ReadLine();
070
}
071
072
073
static
void
ConnectComplete(IAsyncResult ar)
074
{
075
MyObject myObj = ar.AsyncState
as
MyObject;
076
Socket clientSk = myObj.Socket;
077
078
byte
[] datas = System.Text.Encoding.UTF8.GetBytes(
"I always want put things together!"
);
079
clientSk.BeginSend(datas, 0, datas.Length, SocketFlags.None,
new
AsyncCallback(SendComplete),
new
MyObject(clientSk,
"开始发送了"
, datas));
080
081
082
byte
[] buffer =
new
byte
[2048];
//虽然不知道会收到多少,但是多了总比少了好。
083
084
clientSk.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None,
new
AsyncCallback(RecievedComplete),
new
MyObject(clientSk,
"开始接收了"
, buffer));
085
086
}
087
088
static
void
SendComplete(IAsyncResult ar)
089
{
090
MyObject myObj = ar.AsyncState
as
MyObject;
091
Socket sk = myObj.Socket;
092
093
int
sended = sk.EndSend(ar);
094
095
Console.WriteLine(System.Text.Encoding.UTF8.GetString(myObj.Buffer));
096
}
097
098
static
void
RecievedComplete(IAsyncResult ar)
099
{
100
101
MyObject myObj = ar.AsyncState
as
MyObject;
102
Socket sk = myObj.Socket;
103
104
int
recieved = sk.EndReceive(ar);
105
106
Console.WriteLine(System.Text.Encoding.UTF8.GetString(myObj.Buffer));
107
}
108
}
109
}
1
<img src=
"http://pic002.cnblogs.com/images/2011/79702/2011070520391854.jpg"
><br>
The end.
附:
启动第一个项目
启动第二个...第N个
代码下载:
- C#socket资料汇总
- c# socket 资料汇总
- C++/CLI资料汇总
- C语言资料汇总
- Objective-C 学习资料汇总
- C语言书籍资料汇总
- VC++/MFC/C/C++ 资料下载汇总
- 资料汇总
- 资料汇总
- 资料汇总
- 资料汇总
- 资料汇总
- 资料汇总
- 资料汇总
- 资料汇总
- C语言、C++、VC电子资料(电子书+视频)下载汇总
- [C++/CLI编程宝典][1]C++/CLI资料汇总
- [C++/CLI编程宝典][1]C++/CLI资料汇总
- Ubuntu 12.04 VNC server 5.0.x [RealVNC] 的配置和使用
- 常用23种设计模式总结,UML图、意图和适用性
- python 使用ioctl() 获得网卡IP 和MAC地址
- *高通camera基本代码架构
- Java中的运行时堆栈
- C#socket资料汇总
- 关键字 strong、week
- 更改点后输出把集合里的点通过树的边连在一起所需要的最小代价 LCA+树状数组 HDU 5296 Annoying problem
- 论文笔记 《Deep Neural Networks for Object Detection》
- 后端分布式系列:分布式存储-HDFS NameNode 设计实现解析
- scott用户添加debug权限
- android网络编程所涉及到的知识
- iOS学习——ScrollView图片轮播和同类控件优先级问题
- Android 中 PopupWindow 响应返回键并关闭的问题