c# socket 资料汇总

     最近需要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实例:

双击代码全选
1
IPAddressmyIP=IPAddress.Parse( "192.168.0.1" );

  需要知道的是:Socket类支持两种基本模式:同步和异步。其区别在于:在同步模式中,按块传输,对执行网络操作的函数(如Send和 Receive)的调用一直等到所有内容传送操作完成后才将控制返回给调用程序。在异步模式中,是按位传输,需要指定发送的开始和结束。同步模式是最常用的模式,我们这里的例子也是使用同步模式。

  下面看一个完整的例子,client向server发送一段测试字符串,server接收并显示出来,给予client成功响应。

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
//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

01using System;
02using System.Collections.Generic;
03using System.Text;
04using System.Net.Sockets;
05using System.Net;
06 
07namespace 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:

01using System;
02using System.Collections.Generic;
03using System.Text;
04using System.Net.Sockets;
05using System.Net;
06 
07namespace 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

001using System;
002using System.Collections.Generic;
003using System.Text;
004using System.Net.Sockets;
005using System.Net;
006 
007namespace 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

001using System;
002using System.Collections.Generic;
003using System.Text;
004using System.Net.Sockets;
005using System.Net;
006 
007namespace 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}

The end.

附:

启动第一个项目

启动第二个...第N个

代码下载

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

似水流年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值