加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

C#socket、TCP、UDP通信

(2013-05-17 17:38:32)
标签:

c、socket、tcp、udp

it

分类: MissCombanc

一、        C# Socket TCP&UDP

转:http://www.soaspx.com/dotnet/csharp/csharp_20120718_9423.html

程序员可以通过Socket来发送和接收网络上的数据,可以理解为一个API

C#中,MS提供了System.Net.Sockets命名空间,里面包含Socket类。

1.       socket来访问网络。

访问网络的基本条件:a. 确定本机IP和端口号,socket只有与某IP和端口号绑定,才能发挥威力;b. 协议,可以自己定,还有比如UDPTCP

下面是访问网络的步骤:

1)  建立一个套接字。

2)  绑定本机IP和端口号。

3)  如果是TCP,由于其是面向连接的,需要Listen()方法监听网络上是否有人给自己发东西;如果是UDP,因为是无连接的,所以来者不拒。

4)  TCP情况下,如果监听到一个连接,就可以使用accept来接收这个连接,然后就可以利用Send/Receive来执行操作了。而UDP,则不需要accept,直接使用SendTo/ReceiveFrom来执行操作。(UDP由于不需要建立连接,所以发送前不知道对方IP和端口号,因此需要指定一个发送的节点才能进行正常发送和接收)

5)  如果不想发送和接收了,就不要浪费资源了,能closeclose

 

2.  代码实现:

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace tcpserver
{
    /// 
    /// Class1 
的摘要说明。
    /// 
    class server
    {
        /// 
        /// 
应用程序的主入口点。
        /// 
        [STAThread]
        static void Main(string[] args)
        {
            //
            // TODO: 
在此处添加代码以启动应用程序
            //
            int recv;//
用于表示客户端发送的信息长度
            byte[] data=new byte[1024];//
用于缓存客户端所发送的信息,通过socket传递的信息必须为字节数组
            IPEndPoint ipep=new IPEndPoint(IPAddress.Any,9050);//
本机预使用的IP和端口
            Socket newsock=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
            newsock.Bind(ipep);//
绑定
            newsock.Listen(10);//
监听
            Console.WriteLine("waiting for client ");
            Socket client=newsock.Accept();//
当有可用的客户端连接尝试时执行,并返回一个新的socket,用于与客户端之间的通信
            IPEndPoint clientip=(IPEndPoint)client.RemoteEndPoint;
            Console.WriteLine("connect with client:"+clientip.Address+" at port:"+clientip.Port);
            string welcome="welcome here!";
            data=Encoding.ASCII.GetBytes(welcome);
            client.Send(data,data.Length,SocketFlags.None);//
发送信息
            while(true)
            {//
用死循环来不断的从客户端获取信息
                data=new byte[1024];
                recv=client.Receive(data);
                Console.WriteLine("recv="+recv);
                if (recv==0)//
当信息长度为0,说明客户端连接断开
                    break;
                Console.WriteLine(Encoding.ASCII.GetString(data,0,recv));
                client.Send(data,recv,SocketFlags.None);
            }
            Console.WriteLine("Disconnected from"+clientip.Address);
            client.Close();
            newsock.Close();

        }
    }
}


using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace tcpclient
{
    /// 
    /// Class1 
的摘要说明。
    /// 
    class client
    {
        /// 
        /// 
应用程序的主入口点。
        /// 
        [STAThread]
        static void Main(string[] args)
        {
            //
            // TODO: 
在此处添加代码以启动应用程序
            //
            byte[] data=new byte[1024];
            Socket newclient=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
            Console.Write("please input the server ip:");
            string ipadd=Console.ReadLine();
            Console.WriteLine();
            Console.Write("please input the server port:");
            int port=Convert.ToInt32(Console.ReadLine());
            IPEndPoint ie=new IPEndPoint(IPAddress.Parse(ipadd),port);//
服务器的IP和端口
            try
            {
                //
因为客户端只是用来向特定的服务器发送信息,所以不需要绑定本机的IP和端口。不需要监听。
                newclient.Connect(ie);
            }
            catch(SocketException e)
            {
                Console.WriteLine("unable to connect to server");
                Console.WriteLine(e.ToString());
                return;
            }
            int recv newclient.Receive(data);
            string stringdata=Encoding.ASCII.GetString(data,0,recv);
            Console.WriteLine(stringdata);
            while(true)
            {
                string input=Console.ReadLine();
                if(input=="exit")
                    break;
                newclient.Send(Encoding.ASCII.GetBytes(input));
                data=new byte[1024];
                recv=newclient.Receive(data);
                stringdata=Encoding.ASCII.GetString(data,0,recv);
                Console.WriteLine(stringdata);
            }
            Console.WriteLine("disconnect from sercer ");
            newclient.Shutdown(SocketShutdown.Both);
            newclient.Close();

        }
    }

下面在给出无连接的(实在是太懒了,下面这个是直接复制别人的)
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace SimpleUdpSrvr
{
    class Program
    {
        static void Main(string[] args)
        {
            int recv;
            byte[] data new byte[1024];
            IPEndPoint ipep new IPEndPoint(IPAddress.Any, 9050);//
定义一网络端点
            Socket newsock new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);//
定义一个Socket
            newsock.Bind(ipep);//Socket
与本地的一个终结点相关联
            Console.WriteLine("Waiting for client ..");

            IPEndPoint sender new IPEndPoint(IPAddress.Any, 0);//
定义要发送的计算机的地址
            EndPoint Remote (EndPoint)(sender);//
            recv newsock.ReceiveFrom(data, ref Remote);//
接受数据           
            Console.WriteLine("Message received from{0}:", Remote.ToString());
            Console.WriteLine(Encoding.ASCII.GetBytes(data,0,recv));

            string welcome "Welcome to my test server!";
            data Encoding.ASCII.GetBytes(welcome);
            newsock.SendTo(data, data.Length, SocketFlags.None, Remote);
            while (true)
            {
                data new byte[1024];
                recv newsock.ReceiveFrom(data, ref Remote);
                Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));
                newsock.SendTo(data, recv, SocketFlags.None, Remote);
            }
        }
    }
}

 

 

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace SimpleUdpClient
{
    class Program
    {
        static void Main(string[] args)
        {
            byte[] data new byte[1024];//
定义一个数组用来做数据的缓冲区
            string input, stringData;
            IPEndPoint ipep new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9050);
            Socket server new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            string welcome "Hello,are you there?";
            data Encoding.ASCII.GetBytes(welcome);
            server.SendTo(data, data.Length, SocketFlags.None, ipep);//
将数据发送到指定的终结点

            IPEndPoint sender new IPEndPoint(IPAddress.Any, 0);
            EndPoint Remote (EndPoint)sender;
            data new byte[1024];
            int recv server.ReceiveFrom(data, ref Remote);//
接受来自服务器的数据

            Console.WriteLine("Message received from{0}:", Remote.ToString());
            Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));
            while (true)//
读取数据
            {
                input Console.ReadLine();//
从键盘读取数据
                if (input == "text")//
结束标记
                {
                    break;
                }
                server.SendTo(Encoding.ASCII.GetBytes(input), Remote);//
将数据发送到指定的终结点Remote
                data new byte[1024];
                recv server.ReceiveFrom(data, ref Remote);//
Remote接受数据
                stringData Encoding.ASCII.GetString(data, 0, recv);
                Console.WriteLine(stringData);
            }
            Console.WriteLine("Stopping client");
            server.Close();
        }
    }
      

     上面的示例只是简单的应用了socket来实现通信,你也可以实现异步socketIP组播 等等。

     MS还为我们提供了几个助手类:TcpClient类、TcpListener类、UDPClient类。这几个类简化了一些操作,所以你也可以利用这几类来写上面的代码,但我个人还是比较习惯直接用socket来写。
      
     
既然快写完了,那我就再多啰嗦几句。在需要即时响应的软件中,我个人更倾向使用UDP来实现通信,因为相比TCP来说,UDP占用更少的资源,且响应速度快,延时低。至于UDP的可靠性,则可以通过在应用层加以控制来满足。当然如果可靠性要求高的环境下,还是建议使用TCP

二、        TcpClient TcpListenerUdpClient

应用程序可以通过 TCPClientTCPListener UDPClient 类使用传输控制协议 (TCP) 和用户数据文报协议 (UDP) 服务。这些协议类建立在 System.Net.Sockets.Socket 类的基础之上,负责数据传送的细节。(也就是说TCPClientTCPListener UDPClient 类是用来简化Socket)

TcpClient TcpListener 使用 NetworkStream 类表示网络。使用 GetStream 方法返回网络流,然后调用该流的 Read Write 方法。NetworkStream 不拥有协议类的基础套接字,因此关闭它并不影响套接字。

UdpClient 类使用字节数组保存 UDP 数据文报。使用 Send 方法向网络发送数据,使用 Receive 方法接收传入的数据文报。

1.TcpClient
    TcpClient 类提供了一些简单的方法,用于在同步阻止模式下通过网络来连接、发送和接收流数据。为使 TcpClient 连接并交换数据,使用 TCP ProtocolType 创建的 TcpListener  Socket 必须侦听是否有传入的连接请求。可以使用下面两种方法之一连接到该侦听器:

1)创建一个 TcpClient,并调用三个可用的 Connect 方法之一。
2)使用远程主机的主机名和端口号创建 TcpClient。此构造函数将自动尝试一个连接。
    给继承者的说明要发送和接收数据,请使用 GetStream 方法来获取一个 NetworkStream
。调用 NetworkStream  Write Read 方法与远程主机之间发送和接收数据。使用 Close 方法释放与 TcpClient 关联的所有资源。

    下面的例子给出怎么利用TcpClient连接到服务器:

using System;

using System.Net.Sockets;

using System.Text;

using System.Net;

 

 

namespace Tcpclient

{

    public class TcpTimeClient

    {

        private static int portNum = 11000;

        private static string hostName = Dns.GetHostName().ToString();

 

        public static void Main(String[] args)

        {

            try

            {

                TcpClient client = new TcpClient(hostName, portNum);

 

                NetworkStream ns = client.GetStream();

 

                byte[] bytes = new byte[1024];

                int bytesRead = ns.Read(bytes, 0, bytes.Length);

 

                Console.WriteLine(Encoding.ASCII.GetString(bytes, 0, bytesRead));

 

                client.Close();

 

            }

            catch (Exception e)

            {

                Console.WriteLine(e.ToString());

            }

 

          

            Console.Read();

        }

    }

}

2.TcpListener
   
TcpListener 类提供一些简单方法,用于在阻止同步模式下侦听和接受传入连接请求。可使用 TcpClient  Socket 来连接 TcpListener。可使用 IPEndPoint、本地 IP 地址及端口号或者仅使用端口号,来创建 TcpListener。可以将本地 IP 地址指定为Any,将本地端口号指定为 0(如果希望基础服务提供程序为您分配这些值)。如果您选择这样做,可在连接套接字后使用LocalEndpoint 属性来标识已指定的信息。

    Start 方法用来开始侦听传入的连接请求。Start 将对传入连接进行排队,直至您调用 Stop 方法或它已经完成 MaxConnections 排队为止。可使用 AcceptSocket  AcceptTcpClient 从传入连接请求队列提取连接。这两种方法将阻止。如果要避免阻止,可首先使用 Pending 方法来确定队列中是否有可用的连接请求。

    调用 Stop 方法来关闭 TcpListener

    下面的例子给出怎么利用TcpListener监听客户端的请求:

using System;

using System.Net.Sockets;

using System.Text;

 

namespace Tcplistener

{

    public class TcpTimeServer

    {

 

        private const int portNum = 11000;

 

        public static int Main(String[] args)

        {

            bool done = false;

 

            TcpListener listener = new TcpListener(portNum);

 

            listener.Start();

 

            while (!done)

            {

                Console.Write("Waiting for connection...");

                TcpClient client = listener.AcceptTcpClient();

 

                Console.WriteLine("Connection accepted.");

                NetworkStream ns = client.GetStream();

 

                byte[] byteTime = Encoding.ASCII.GetBytes(DateTime.Now.ToString());

 

                try

                {

                    ns.Write(byteTime, 0, byteTime.Length);

                    ns.Close();

                    client.Close();

                }

                catch (Exception e)

                {

                    Console.WriteLine(e.ToString());

                }

            }

 

            listener.Stop();

 

            return 0;

        }

 

    }

}

3.UdpClient
  
 UdpClient 类提供了一些简单的方法,用于在阻止同步模式下发送和接收无连接 UDP 数据报。因为 UDP 是无连接传输协议,所以不需要在发送和接收数据前建立远程主机连接。但您可以选择使用下面两种方法之一来建立默认远程主机:

使用远程主机名和端口号作为参数创建 UdpClient 类的实例。

创建 UdpClient 类的实例,然后调用 Connect 方法。

   可以使用在 UdpClient 中提供的任何一种发送方法将数据发送到远程设备。使用 Receive 方法可以从远程主机接收数据。
   UdpClient
方法还允许发送和接收多路广播数据报。使用 JoinMulticastGroup 方法可以将 UdpClient 预订给多路广播组。使用 DropMulticastGroup 方法可以从多路广播组中取消对 UdpClient 的预订。

   下面的例子演示同一主机不同端口之间的UDP通信:

监听端:

using System;

using System.Net.Sockets;

using System.Text;

using System.Net;

 

namespace Udpclient2

{

    class Program

    {

        static void Main(string[] args)

        {

            UdpClient udpClient = new UdpClient(12000);

          

                try

                {

                    IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);

                    Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);

                    string returnData = Encoding.ASCII.GetString(receiveBytes);

                    while (returnData != "")

                    {

                        udpClient.Connect(RemoteIpEndPoint.Address.ToString(), Convert.ToInt32(RemoteIpEndPoint.Port));

                        Byte[] sendBytes = Encoding.ASCII.GetBytes("I'm here.");

 

                        udpClient.Send(sendBytes, sendBytes.Length);

 

                        Console.WriteLine("This is the message you received " +

                                                     returnData.ToString());

                        Console.WriteLine("This message was sent from " +

                                                    RemoteIpEndPoint.Address.ToString() +

                                                    " on their port number " +

                                                    RemoteIpEndPoint.Port.ToString());

 

                        udpClient.Close();

                        break;

                    }

                }

                catch (Exception e)

                {

                    Console.WriteLine(e.ToString());

                }

          

            Console.Read();

        }

    }

}

连接端:

using System;

using System.Net.Sockets;

using System.Text;

using System.Net;

 

namespace Udpclient

{

    class Program

    {

        static void Main(string[] args)

        {

            // This constructor arbitrarily assigns the local port number.

            UdpClient udpClient = new UdpClient(11000);

            try

            {

                udpClient.Connect(Dns.GetHostName().ToString(), 12000);

 

                // Sends a message to the host to which you have connected.

                Byte[] sendBytes = Encoding.ASCII.GetBytes("Is anybody there?");

 

                udpClient.Send(sendBytes, sendBytes.Length);

 

              

 

                //IPEndPoint object will allow us to read datagrams sent from any source.

                IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);

 

                // Blocks until a message returns on this socket from a remote host.

                Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);

                string returnData = Encoding.ASCII.GetString(receiveBytes);

 

                // Uses the IPEndPoint object to determine which of these two hosts responded.

                Console.WriteLine("This is the message you received " +

                                             returnData.ToString());

                Console.WriteLine("This message was sent from " +

                                            RemoteIpEndPoint.Address.ToString() +

                                            " on their port number " +

                                            RemoteIpEndPoint.Port.ToString());

 

                udpClient.Close();

 

            }

            catch (Exception e)

            {

                Console.WriteLine(e.ToString());

            }

            Console.Read();

 

        }

    }

}

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有