Socket笔记(一)

1.基于Tcp协议的Socket通讯

服务端

使用Tcp协议通讯需要具备以下几个条件:
(1).建立一个套接字(Socket) (固定写法,第一个参数是因特网,第二个参数是用流来进行传输,第三个参数是协议的类型。这里选TCP协议)

Socket tcpServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

(2).绑定服务器端IP地址及端口号(输入你自己电脑的ip)

TcpSever.Bind(new IPEndPoint(IPAddress.Parse("10.198.1.237"), 9900));

IPEndPoint(第一个参数是IP地址,第二个参数是端口号,这个端口号是自己设定的。尽量设定大一点的端口号(也不要太大,4位数就好了),防止与电脑的其他应用程序冲突。)
实用工具类-IPAddress

IPAddress ipAddress = IPAddress.Parse("234.34.5.3");  
byte[] address = ipAddress.GetAddressBytes();//得到四个位置上的具体值  
string ipString = ipAddress.ToString();//得到ip的字符串

(3).利用Listen()方法开启监听,设置客户端的最大连接数量。

TcpSever.Listen(100);

(4).利用Accept()方法尝试与客户端建立一个连接,返回一个连接的客户端的Socket.可以得到连接的客户端的IP和端口

Socket clientSocket = TcpSever.Accept();

(5).利用Send()方法向建立连接的主机发送消息 ,要发送的消息要转为字节数组,才能发送。

string sendMessage = "Welcome to this Sever!";
//转格式API
byte[] SendData = Encoding.UTF8.GetBytes(sendMessage);
clientSocket.Send(SendData);

(6).利用Recive()方法接受来自建立连接的主机的消息

//接受客户端的消息
//新建一个字节数组容器,容量按实际情况设定,测试的话1024足够用了
byte[] ReceiveData = new byte[1024];
//接收的数据的长度
int Length = clientSocket.Receive(ReceiveData);
//接收的字节数组转为字符串格式
string ReceivedMessage = Encoding.UTF8.GetString(ReceiveData, 0, Length);
//打印从客户端接收到的消息
Console.WriteLine(ReceivedMessage);

客户端

(1).建立一个套接字(Socket)

Socket ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

(2).利用Connect()方法与服务器建立连接(填主机的IP和端口)

ClientSocket.Connect(new IPEndPoint(IPAddress.Parse("10.198.1.237"), 9900));

(3).利用Send()方法向建立连接的主机发送消息

 //发送消息到服务端
string SendMessage = Console.ReadLine();
byte[] SendData = Encoding.UTF8.GetBytes(SendMessage);
ClientSocket.Send(SendData);

(4).利用Recive()方法接受来自建立连接的主机的消息

//接收服务端的消息
byte[] ReceivedData = new byte[1024];
int length = ClientSocket.Receive(ReceivedData);
string ReceivedMessage = Encoding.UTF8.GetString(ReceivedData, 0, length);
Console.WriteLine(ReceivedMessage);

服务器端完整代码:

using System;
using System.Collections.Generic;
using System.Linq;
usingSystem.Net;
usingSystem.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace TCP_Sever
{
    class Program
    {
        static List<ClientedSocket> ClientList= new List<ClientedSocket>();
        static void Main(string[] args)
        {
           //一:新建一个Socket
               Socket TcpSever = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //一:绑定ip
            TcpSever.Bind(new IPEndPoint(IPAddress.Parse("10.198.1.237"), 9900));
            //设置客户端最大连接数量
            TcpSever.Listen(100);
            Console.WriteLine("Sever is running-----");
            Socket clientSocket = TcpSever.Accept();
            //发送给客户端
            string sendMessage = "Welcome to this Sever!";
            byte[] SendData = Encoding.UTF8.GetBytes(sendMessage);
            clientSocket.Send(SendData);
            //接受客户端的消息
            byte[] ReceiveData = new byte[1024];
            int Length = clientSocket.Receive(ReceiveData);
            string ReceivedMessage = Encoding.UTF8.GetString(ReceiveData, 0, Length);
            Console.WriteLine(ReceivedMessage);
            Console.ReadKey();
        }
    }
}

客户端完整代码:

using System;
using System.Collections.Generic;
using System.Linq;
usingSystem.Net;
usingSystem.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace TCP_Client
{
    class Program
    {
        private static Socket ClientSocket;
        static void Main(string[] args)
        {
            ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            ClientSocket.Connect(new IPEndPoint(IPAddress.Parse("10.198.1.12"), 9900));
            //接收服务端的消息
            byte[] ReceivedData = new byte[1024];
            int length = ClientSocket.Receive(ReceivedData);
            string ReceivedMessage = Encoding.UTF8.GetString(ReceivedData, 0, length);
            Console.WriteLine(ReceivedMessage);
            //发送消息到服务端
            string SendMessage = Console.ReadLine();
            byte[] SendData = Encoding.UTF8.GetBytes(SendMessage);
            ClientSocket.Send(SendData);
            Console.ReadKey();    
        } 
    }
}

测试结果:
在这里插入图片描述
现在客户端和服务器只能互相收发一次消息,要怎么才能互相发送和接收多次消息呢?

服务器代码改进:现在服务器只负责连接客户端。数据的发送和接收交给连接进来的那个Socket

using System;
using System.Collections.Generic;
using System.Linq;
usingSystem.Net;
usingSystem.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace TCP_Sever
{
    class Program
    {
        static List<ClientedSocket> ClientList= new List<ClientedSocket>();
        static void Main(string[] args)
        {
           //一:新建一个Socket
            Socket TcpSever = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //一:绑定ip
            TcpSever.Bind(new IPEndPoint(IPAddress.Parse("10.198.1.12"), 9900));
            //设置客户端最大连接数量
            TcpSever.Listen(100);
            Console.WriteLine("Sever is running-----");
            while (true)
            {
                Socket clientSocket = TcpSever.Accept();
                Console.WriteLine("a client is connect");
                //新建一个类,用来处理连接进来的客户端的逻辑
                ClientedSocket Client = new ClientedSocket(clientSocket);
                Client.SendMessage(" you are connected");
               // 把连接的Socket存起来,为了以后做数据分发
                ClientList.Add(Client);
            }
        }
        //数据分发的方法,就是给客户端发送消息
        public  static void BroadCastMessage(string msg)
        {
            //新建一个用来保存客户端连接断开的Socket
            var NotConnectList = new List<ClientedSocket>();
            //遍历找到所以已经连接服务器的客户端
            foreach (var Client in ClientList)
            { //如果连接没有断开,就发送消息
                if(Client.Connect())
                {
                    Client.SendMessage(msg);
                }
                else//否则加入到没有连接的客户端的列表里
                {
                    NotConnectList.Add(Client);
                }
            }
            //遍历断开的列表,从连接的列表里移除已经断开的Socket
            foreach (var item in NotConnectList)
            {
                ClientList.Remove(item);
            }
        }
    }
}

新建一个类,把接收的客户端的Socket存起来

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
usingSystem.Net;
usingSystem.Net.Sockets;
using System.Threading;

namespace TCP_Sever
{
    class ClientedSocket
    {
        private Socket clientedSocket;
        private Thread t;
        private byte[] ReceivedData = new byte[1024];
   //这个类在构造的时候就传入一个连接客户端的SOCKET。我们在这里循环的接收客户端发来的消息
        public ClientedSocket(Socket ClientedSocket)
        {
            this.clientedSocket = ClientedSocket;
            //启动一个线程,处理客户端的数据接收
            t = new Thread(ReceiveMessage);
            t.Start();
        }
        private void ReceiveMessage()
        {
            try
            {
                //一直接收
                while (true)
                {
                    //在接收数据之前 判断一下Socket连接是否断开
                    if (clientedSocket.Poll(10, SelectMode.SelectRead))
                    {
                        clientedSocket.Shutdown(SocketShutdown.Both);
                        clientedSocket.Close();
                        break;
                    }
                    int length = clientedSocket.Receive(ReceivedData);
                    string ReceivedMessage = Encoding.UTF8.GetString(ReceivedData, 0, length);
                    Console.WriteLine("收到了消息:" + ReceivedMessage);
                    //数据分发:把客户端的发来的消息分发给所有已经连接的客户端,这样的就可以实现数据的同步了
                    Program.BroadCastMessage(ReceivedMessage);
                }
            }
            catch(Exception e)
            {
                //Console.WriteLine(e);
                clientedSocket.Shutdown(SocketShutdown.Both);
                clientedSocket.Close();
            }
        }
   //封装的一个发送消息的方法
        public void SendMessage(string msg)
        {
            byte[] SendData = Encoding.UTF8.GetBytes(msg);
            clientedSocket.Send(SendData);
        }
   //这个方法返回自己的SOCKET是否连接。用来在分发消息的时候做判断
        public bool Connect()
        {
           return clientedSocket.Connected;
        }
    }
}

客户端代码改进:

using System;
using System.Collections.Generic;
using System.Linq;
usingSystem.Net;
usingSystem.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace TCP_Client
{
    class Program
    {
        private static Socket ClientSocket;
        static void Main(string[] args)
        {
            ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            ClientSocket.Connect(new IPEndPoint(IPAddress.Parse("10.198.1.12"), 9900));
     //开一个线程用来专门接收消息
            Thread t = new Thread(ReceiveMessage);
            t.Start();
     //主线程用While循环来接收输入并发送
            while (true)
            {
                //发送消息到服务端
                string SendMessage = Console.ReadLine();
                byte[] SendData = Encoding.UTF8.GetBytes(SendMessage);
                ClientSocket.Send(SendData);
            }
        }
        //这是用来接收消息的方法
        private static void ReceiveMessage()
        {
           //用一个while循环不停的接收
            while (true)
            {
                //判断一下,如果连接断开了就不接收了
                if (ClientSocket.Connected == false)
                {
                    break;
                }
                //接收服务端的消息
                byte[] ReceivedData = new byte[1024];
                int length = ClientSocket.Receive(ReceivedData);
                string ReceivedMessage = Encoding.UTF8.GetString(ReceivedData, 0, length);
                Console.WriteLine(ReceivedMessage);
            }
        }
    }
}

测试结果:
在这里插入图片描述

2.基于Udp协议是无连接模式通讯

占用资源少,响应速度快,延时低。至于可靠性,可通过应用层的控制来满足。(不可靠连接)

服务器端:

(1).建立一个套接字(Socket)

udpClient = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

(2).绑定服务器端IP地址及端口号–服务器端

udpClient.Bind(new IPEndPoint(IPAddress.Parse("10.198.1.237"), 7070));

(3).通过SendTo()方法向指定主机发送消息 (需提供主机IP地址及端口)

string Message = Console.ReadLine();
byte[] SendData = Encoding.UTF8.GetBytes(Message);
udpClient.SendTo(SendData, SeverEndPoint);

4).通过ReciveFrom()方法接收指定主机发送的消息 (需提供主机IP地址及端口)

//接收数据,接收所以ip地址发来的消息。端口写0是为了让他自己初始化
EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
// 新建一个数据容器
byte[] ReceiveData = new byte[1024];
// 接收消息,返回一个长度
int length = udpClient.ReceiveFrom(ReceiveData, ref remoteEndPoint);
// 把接收的长度的数据转换成字符串
string ReceivedMessage = Encoding.UTF8.GetString(ReceiveData, 0, length);
Console.WriteLine(ReceivedMessage);

客户端:

(1).建立一个套接字(Socket)
(2).绑定自己的IP地址及端口号
(3).通过SendTo()方法向指定主机发送消息 (需提供主机IP地址及端口)  
(4).通过ReciveFrom()方法接收指定主机发送的消息 (需提供主机IP地址及端口)

可能你们已经看出来了。udp协议即是客户端也是服务端 因为他不需要连接。只需要对方的ip和端口就能发送发送了和接收消息了
服务器完整代码:我把发来消息的客户端的socket存起来了。

using System;
using System.Collections.Generic;
using System.Linq;
usingSystem.Net;
usingSystem.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace UDP_Sever
{
    class Program
    {
        private static Thread t;
        private static Socket udp_sever;
        private static List<EndPoint> Client_list=new List<EndPoint>();
        private static IPEndPoint NoendPoint;
        
        static void Main(string[] args)
        {
            NoendPoint=new IPEndPoint(IPAddress.Parse("0.0.0.0"), 0);
            //创建Socket
            udp_sever = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            //绑定IP和端口
            udp_sever.Bind(new IPEndPoint(IPAddress.Parse("10.198.1.237"), 8080));
            Console.WriteLine("sever is running------");
            t = new Thread(ReceiveMessage); 
            t.Start();
            Console.ReadKey();
        }
        
        private static void ReceiveMessage()
        {
            while(true)
            {
                //接收数据
                EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
                byte[] ReceiveData = new byte[1024];
                int length = udp_sever.ReceiveFrom(ReceiveData, ref remoteEndPoint);
                string ReceivedMessage = Encoding.UTF8.GetString(ReceiveData, 0, length);
                Console.WriteLine("从ip: " + (remoteEndPoint as IPEndPoint).Address.ToString() + ": "
                    + (remoteEndPoint as IPEndPoint).Port.ToString() + "发来消息: " + ReceivedMessage);
                // byte[] SendData = Encoding.UTF8.GetBytes(ReceivedMessage);        
                if (!Client_list.Contains(remoteEndPoint)&& (remoteEndPoint as IPEndPoint).Address.ToString()!="0.0.0.0")
                {
                    Client_list.Add(remoteEndPoint);
                }
                //  udp_sever.SendTo(SendData, remoteEndPoint);
                broadcastMessage(ReceivedMessage);
            }
        }
        
        private static void broadcastMessage(string msg)
        {
            byte[] SendData = Encoding.UTF8.GetBytes(msg);
            foreach (EndPoint item in Client_list)
            {
              //  Console.WriteLine("item   " + item);
                udp_sever.SendTo(SendData, item);
            }        
        }
    }
}

客户端完整代码:

using System;
using System.Collections.Generic;
using System.Linq;
usingSystem.Net;
usingSystem.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace UDP_Client
{
    class Program
    {
        private static Socket udpClient;
        private static Thread T;
        private static EndPoint SeverEndPoint;
        
        static void Main(string[] args)
        {
            //创建Socket
            udpClient = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            //绑定自己的IP和端口
            udpClient.Bind(new IPEndPoint(IPAddress.Parse("10.198.1.237"), 7070));
            //发送数据
            SeverEndPoint = new IPEndPoint(IPAddress.Parse("10.198.1.237"), 8080);
          T = new Thread(ReceivedMessage);
          T.Start();
            while (true)
            {
                string Message = Console.ReadLine();
                byte[] SendData = Encoding.UTF8.GetBytes(Message);
                udpClient.SendTo(SendData, SeverEndPoint);
            }
        }
        
        private static void ReceivedMessage()
        {
            while(true)
            {
                //接收数据
                EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
                byte[] ReceiveData = new byte[1024];
                int length = udpClient.ReceiveFrom(ReceiveData, ref remoteEndPoint);
                string ReceivedMessage = Encoding.UTF8.GetString(ReceiveData, 0, length);
                Console.WriteLine(ReceivedMessage);
            }
        }
    }
}

测试结果,和tcp连接效果一样:
在这里插入图片描述

3.Tcp和Udp的区别

1.基于连接与无连接;
2.对系统资源的要求(TCP较多,UDP少);
3.UDP程序结构较简单;
4.流模式与数据报模式 ;
5.TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值