Socket通讯实例-基本Socket

转自:http://www.cnblogs.com/mahaisong/archive/2011/07/25/2116475.html (讲的很好,很细)

参考:http://blog.sina.com.cn/s/blog_810c860001018tir.html

连接握手:

1.客户端发送建立连接请求
2.服务端确认连接请求
3.客户端确认已经连接
以上3步完成后即可使用send recv了
 
断开握手:如果要正确断开必须经过4次握手。
1.客户端发送请求停止TCP连接请求
2.服务端收到请求后将这一个socket关闭
3.服务端发送反向请求客户端关闭socket连接
4.客户端确认服务端请求,关闭socket连接。

示例程序是同步套接字程序,功能很简单,只是客户端发给服务器一条信息,服务器向客户端返回一条信息;,是一个最基本的socket编程流程,依次记录套接字的同步和异步,以及它们的区别。

 

下面是示例程序的简单步骤说明

服务器端:

第一步:用指定的端口号和服务器的ip建立一个EndPoint对像;

第二步:建立一个Socket对像;

第三步:用socket对像的Bind()方法绑定EndPoint;

第四步:用socket对像的Listen()方法开始监听;

第五步:接受到客户端的连接,用socket对像的Accept()方法创建新的socket对像用于和请求的客户端进行通信;

第六步:通信结束后一定记得关闭socket;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
 
namespace Server
{
    class Program
    {
        static void Main(string[] args) {
 
            int port = 2000;//端口号码
            string host = "127.0.0.1";//服务器主机
 
 
            ///创建终结点(EndPoint)
 
            //IPAddress 类包含计算机在 IP 网络上的地址。
            //IPAddress..Parse 方法 (将 IP 地址字符串转换为 IPAddress 实例。)
 
            IPAddress ip = IPAddress.Parse(host);
 
 
            //将网络端点表示为 IP 地址和端口号。
            //IPEndPoint 类包含应用程序连接到主机上的服务所需的主机和本地或远程端口信息。
            //通过组合服务的主机 IP 地址和端口号,IPEndPoint 类形成到服务的连接点。
 
            IPEndPoint ipe = new IPEndPoint(ip, port);//用指定的地址和端口号初始化 IPEndPoint 类的新实例。
 
            // end 终结的创建
 
 
       //Socket经解
                //Socket 类对异步方法遵循 .NET Framework 命名模式。例如,同步的 Receive 方法对应于异步的 BeginReceive 和 EndReceive 方法。
 
              //如果应用程序在执行期间只需要一个线程,请使用下面的方法,这些方法适用于同步操作模式。
 
            //如果当前使用的是面向连接的协议(如 TCP),则服务器可以使用 Listen 方法侦听连接。
 
            //  Accept 方法处理任何传入的连接请求,并返回可用于与远程主机进行数据通信的 Socket。可以使用此返回的 Socket 来调用 Send 或 Receive 方法。
            //如果要指定本地 IP 地址和端口号,请在调用 Listen 方法之前先调用 Bind 方法。
            //如果您希望基础服务提供程序为您分配可用端口,请使用端口号 0。
            //如果希望连接到侦听主机,请调用 Connect 方法。若要进行数据通信,请调用 Send 或 Receive 方法。
 
 
 
           //如果当前使用的是无连接协议(如 UDP),则根本不需要侦听连接。调用 ReceiveFrom 方法可接受任何传入的数据报。
           // 使用 SendTo 方法可将数据报发送到远程主机。
 
 
 
            //若要在执行过程中使用单独的线程处理通信,请使用下面的方法,这些方法适用于异步操作模式。
 
               //如果当前使用的是面向连接的协议(如 TCP),则可使用 Socket、BeginConnect 和 EndConnect 方法来连接侦听主机。
           // 通过使用 BeginSend 和 EndSend 方法,或者使用 BeginReceive 和 EndReceive 方法,可以进行异步数据通信。
            //可以使用 BeginAccept 和 EndAccept 处理传入的连接请求。
 
               //如果您使用的是 UDP 等无连接协议,则可以使用 BeginSendTo 和 EndSendTo 来发送数据报,而使用 BeginReceiveFrom 和 EndReceiveFrom 来接收数据报。
 
                //如果对一个套接字执行多个异步操作,它们不一定按启动时的顺序完成。
             //当数据发送和数据接收完成之后,可使用 Shutdown 方法来禁用 Socket。
            //在调用 Shutdown 之后,可调用 Close 方法来释放与 Socket 关联的所有资源。
            //通过 Socket 类,您可以使用 SetSocketOption 方法来配置 Socket。
           // 可以使用 GetSocketOption 方法来检索这些设置。
 
 
         //说明:
               //如果要编写相对简单的应用程序,而且不需要最高的性能,则可以考虑使用 TcpClient、TcpListener 和 UdpClient。
                //这些类为 Socket 通信提供了更简单、对用户更友好的接口。
 
 
 //Socket经解 完成
 
 
 
 
 
 
 
 
            //创建socket并开始监听
 
            //创建一个socket对像,如果用udp协议,则要用SocketType.Dgram类型(无连接的)的套接字
            //使用指定的地址族(socket使用的寻址方案)、套接字类型(Stream:双向连接)和协议(协议类型)
            //初始化 Socket 类的新实例。
 
            Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 
            //如果需要使用特定的本地终结点,请使用 Bind 方法。必须先调用 Bind,然后才能调用 Listen 方法。
            //在调用 Bind 之前,必须首先创建打算从其进行数据通信的本地 IPEndPoint。
            //如果您不介意分配哪个本地地址,则可以用 IPAddress..::.Any 作为地址参数创建一个 IPEndPoint,
            //这样,基础服务提供程序将会分配最适合的网络地址。如果您有多个网络接口,这将有助于简化您的应用程序。
            //如果您不介意使用哪个本地端口,则可以创建一个使用 0 作为端口号的 IPEndPoint。
            //在这种情况下,服务提供程序将会分配一个可用的端口号(介于 1024 和 5000 之间)。
           //如果使用上面的方法,您可以通过调用 LocalEndPoint 获知所分配的本地网络地址和端口号。
            //如果当前使用的是面向连接的协议,则直到您调用了 Connect 或 EndConnect 方法后,LocalEndPoint 才会返回本地分配的网络地址。
            //如果当前使用的是无连接协议,则直到完成一个发送或接收操作后,才可访问该信息。
 
 
            s.Bind(ipe);//绑定这个socket通信 在这个连接点上。(对应的IP和端口) ,绑定了才能够通信和监听
            ////绑定EndPoint对像(2000端口和ip地址)
 
 
 
            s.Listen(0);//将 Socket 置于侦听状态。
            //Listen 可以让一个面向连接的 Socket 侦听传入的连接尝试。backlog 参数指定队列中最多可容纳的等待接受的传入连接数。
            //可使用 Accept 或 BeginAccept 来接受来自队列的连接。
            //在调用 Listen 之前,必须首先调用 Bind 方法,否则 Listen 将引发 SocketException。
            //socket监听后,如果客户端开始连结,或请求发送数据。 服务端怎么立即就知道有数据传送或连接请求啊--因为Listen
            Console.Write("等待客户端请求,监听中");
 
 
 
 
            //接受到client连接,为此连接建立新的socket,并接受信息
 
            Socket temp = s.Accept();//为新建连接创建新的socket
            //Accept 以同步方式从侦听套接字的连接请求队列中提取第一个挂起的连接请求,然后创建并返回新的 Socket。
            //在阻止模式中,Accept 将一直处于阻止状态,直到传入的连接尝试排入队列。连接被接受后,原来的 Socket 继续将传入的连接请求排入队列,直到您关闭它。
            //在调用 Accept 方法之前,必须首先调用 Listen 方法来侦听传入的连接请求,并将侦听到的请求放入队列中。
 
 
            Console.Write("服务端建立连接……");
 
            Console.Write("请按ENTER,接收客户端消息");
            Console.ReadLine();
 
            string recvStr = "";
            byte[] recvBytes = new byte[1024];
 
            int bytes;
            bytes = temp.Receive(recvBytes, recvBytes.Length, 0);//接收客户端数据  即存入了Byte数组。又返回了长度。
 
            //使用指定的 SocketFlags,从绑定的 Socket 接收指定字节数的数据,并将数据存入接收缓冲区。
            //Byte 类型的数组,它是存储接收到的数据的位置、要接收的字节数。
              //SocketFlags 值的按位组合。0表示不组合。 
            //返回 数据长度
 
            recvStr += Encoding.ASCII.GetString(recvBytes, 0, bytes);
 
 
            //给client端返回信息
         
            Console.Write("服务端得到消息 {0}", recvStr);//把客户端传来的信息显示出来
 
            Console.Write("请按ENTER,发送收到信息给客户端");
            Console.ReadLine();
 
            String sendStr = "OK!Client Send  message  sucessful,Because Me Server received all.";
 
            byte[] sendbytes = Encoding.ASCII.GetBytes(sendStr);
 
            temp.Send(sendbytes, sendbytes.Length, 0);//Send() 将数据发送到连接的 Socket。 
 
            //因为这里是Socket编程。和TCPlisten编程有更高的封装。
            Console.Write("对应客户端的服务要关闭,请按ENTER");
            Console.ReadLine();
 
            temp.Close();//虽然是对应的,可是服务端这里只要回复完了就立即关闭。不管对方怎么样..这里深刻说明了什么叫无状态。
         
            s.Close();
 
            Console.WriteLine();
    
        }
 
 
    }
}
客户端:
第一步:用指定的端口号和服务器的ip建立一个EndPoint对像;

第二步:建立一个Socket对像;

第三步:用socket对像的Connect()方法以上面建立的EndPoint对像做为参数,向服务器发出连接请求;

第四步:如果连接成功,就用socket对像的Send()方法向服务器发送信息;

第五步:用socket对像的Receive()方法接受服务器发来的信息 ;

第六步:通信结束后一定记得关闭socket;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
 
namespace Client
{
    class Program
    {
        static void Main(string [] args) {
 
            int port = 2000;
            string host = "127.0.0.1";
 
            IPAddress ip = IPAddress.Parse(host);
            IPEndPoint ipe = new IPEndPoint(ip,port);
 
 
 
 
            Socket c = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
      
 
            Console.Write("客户端开始连接 ……");
 
            c.Connect(ipe);
            //如果当前使用的是面向连接的协议(如 TCP),则 Connect 方法会同步建立 LocalEndPoint 与指定远程终结点之间的网络连接。
            //如果您使用的是无连接协议,Connect 会建立一个默认远程主机。
            //在调用 Connect 之后,请使用 Send 方法将数据发送到远程设备,或者使用 Receive 方法从远程设备接收数据。
            //如果您使用的是无连接协议(如 UDP),则不必先调用 Connect 即可发送和接收数据。
            //您可以使用 SendTo 和 ReceiveFrom 来与远程主机进行同步通信。
 
         
            //LocalEndPoint 属性获取一个包含 Socket 绑定到的本地 IP 地址和端口号的 EndPoint。
            //您必须将此 EndPoint 强制转换为 IPEndPoint 才能检索信息。
            //然后可以调用 IPEndPoint..::.Address 方法来检索该本地 IPAddress,调用 IPEndPoint..::.Port 方法来检索该本地端口号。
 
             //LocalEndPoint 属性通常是在调用 Bind 方法之后设置的。
            //如果允许系统分配套接字的本地 IP 地址和端口号,则将在第一次 I/O 操作之后设置 LocalEndPoint 属性。
            //对于面向连接的协议而言,第一次 I/O 操作将是对 Connect 或 Accept 方法的调用。
            //而对于无连接的协议而言,第一次 I/O 操作可以是任何发送或接收调用。
 
            Console.Write("客户端连接成功,请按ENTER键,发送给服务器消息");
            Console.ReadLine();
 
          String sendStr="Hello!This is Client TalK!";
 
         byte [] byteSend=Encoding.ASCII.GetBytes(sendStr);
 
              Console.WriteLine("客户端发送消息");
             c.Send(byteSend,byteSend.Length,0);
      
 
 
            //从服务器端接受返回信息
 
 
             string recvStr = "";
 
             byte[] reciveBytes = new byte[1024];
 
             int recive;
 
             recive = c.Receive(reciveBytes, reciveBytes.Length,0);
 
 
             recvStr += Encoding.ASCII.GetString(reciveBytes, 0, recive);
 
             Console.Write("客户端收到服务端发来信息:", recvStr);
 
             Console.Write("客户端要关闭了。请按ENTER");
             Console.ReadLine();
            //这里的关闭也和服务器的没有怎么的关系。这里深刻说明了什么叫无状态。
             c.Close();
         
         
        }
 
    }
}
原文地址:https://www.cnblogs.com/feigao/p/5264494.html