知识引入
弱联网和强联网游戏
- 弱联网游戏:不会频繁的进行数据通信,通常服务端处理完客户端请求就断开连接,例如一些休闲游戏
- 强联网游戏:频繁进行数据通信,游戏核心逻辑在服务端处理,与客户端不停同步信息,例如MOBA,MMO等
TCP、UDP 和 Socket
TCP:TCP 是一种传输层协议,提供面向连接的、可靠的数据传输服务
TCP特点:
1. 面向连接——两者之间必须建立可靠的连接
2. 一对一——只能是1对1的建立连接
3. 可靠性高——消息传送失败会重新发送,不允许丢包
4. 有序的——是按照顺序进行消息发送的
UDP:UDP 是一种传输层协议,提供无连接的、不可靠的数据传输服务
UDP特点:
1. 无连接 —— 两者之间无需建立连接
2. n对n —— TCP只能1对1连接进行消息传递,而UDP由于无连接所以可以n对n
3. 可靠性低 —— 消息可能在传送过程中丢失,丢失后不会重发
4. 传输效率高 —— 由于它的可靠性低并且也无需建立连接,所以传输效率上更高一些
Socket(套接字):一种编程接口,使用TCP或UDP协议进行网络通信
知识点
IPAdress类
//1.通过Byte数组 byte[] ipAddress = new byte[] { 118, 102, 111, 11 }; IPAddress ip1 = new IPAddress(ipAddress); //2.通过Long初始化 IPAddress ip2 = new IPAddress(0x7666F0B); //3.通过字符串转换(推荐) IPAddress ip3 = IPAddress.Parse("118.102.111.11");
IPEndPoint类
IPEndPoint类将网络端点表示为IP地址和端口号,表现为IP地址和端口号的组合
//初始化方式 IPEndPoint ipPoint = new IPEndPoint(0x79666F0B, 8080); IPEndPoint ipPoint2 = new IPEndPoint(IPAddress.Parse("118.102.111.11"), 8080);
Socket类
语法:Socket socketTcp = new Socket(参数1, 参数2, 参数3);
每一个参数都由枚举类型构成,下面列出每个枚举变量常用的参数
参数1:
InterNetwork
IPv4寻址InterNetwork6
IPv6寻址
参数2:Dgram
支持数据报,最大长度固定的无连接、不可靠的消息(主要用于UDP通信)Stream
支持可靠、双向、基于连接的字节流(主要用于TCP通信)
参数3:
TCP
TCP传输控制协议UDP
UDP用户数据报协议
而这里列出常用的搭配方式
2、3参数的常用搭配:SocketType.Dgram + ProtocolType.Udp
= UDP协议通信(常用,主要学习)SocketType.Stream + ProtocolType.Tcp
= TCP协议通信(常用,主要学习)SocketType.Raw + ProtocolType.Icmp
= Internet控制报文协议(了解)SocketType.Raw + ProtocolType.Raw
= 简单的IP包通信(了解)
如何在服务端和客户端间建立通信
- 客户端:
1. 创建套接字Socket
2. 用Connect方法与服务器相连接
3. 用Send和Receive相关方法收发数据
4. 用Shutdown方法释放连接
5. 关闭套接字 - 服务端:
1. 创建套接字Socket
2. 用Bind方法将套接字与本地地址绑定
3. 用Listen方法监听
4. 用Accept方法等待客户端连接
5. 建立连接,Accept返回新套接字
6. 用Send和Receive相关方法收发数据
7. 用Shutdown方法释放连接
8. 关闭套接字
实战
服务端
using System.Net; using System.Net.Sockets; using System.Text; namespace LearnTcpServer; class Program { static void Main(string[] args) { // 1. 创建套接字Socket Socket socketTcp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // 2. 用Bind方法将套接字与本地地址绑定 try { IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8080); socketTcp.Bind(ipEndPoint); } catch (Exception e) { Console.WriteLine("绑定失败"+e.Message); throw; } // 3. 用Listen方法监听 socketTcp.Listen(1); Console.WriteLine("服务端绑定监听结束,等待客户端连入"); // 4. 用Accept方法等待客户端连接 // 5. 建立连接,Accept返回新套接字 Socket socketClient = socketTcp.Accept(); // 6. 用Send和Receive相关方法收发数据 //发送 socketClient.Send(Encoding.UTF8.GetBytes("Welcome to Connect to Server!")); //接收 byte[] result = new byte[1024];//1kb int receiveNum = socketClient.Receive(result); Console.WriteLine("Received Message From {0}:{1}",socketClient.RemoteEndPoint.ToString(),Encoding.UTF8.GetString(result,0,receiveNum)); // 7. 用Shutdown方法释放连接 socketClient.Shutdown(SocketShutdown.Both); // 8. 关闭套接字 socketClient.Close(); Console.WriteLine("服务端已关闭,按任意键退出"); Console.ReadKey(); } }
客户端
using System; using System.Collections; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Text; namespace LearnTcpClient { internal class Program { static void Main(string[] args) { // 1. 创建套接字Socket Socket socketTcp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // 2. 用Connect方法与服务器相连接 try { IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8080); socketTcp.Connect(ipEndPoint); } catch (SocketException e) { if (e.ErrorCode == 10061) { Console.WriteLine("服务器拒绝连接"); } else { Console.WriteLine("连接失败" + e.ErrorCode); } return; } // 3. 用Send和Receive相关方法收发数据 byte[] result = new byte[1024]; int receiveNum = socketTcp.Receive(result); Console.WriteLine($"Received Message From {socketTcp.RemoteEndPoint.ToString()}:{Encoding.UTF8.GetString(result, 0, receiveNum)}"); socketTcp.Send(Encoding.UTF8.GetBytes("Hello i'm client!")); // 4. 用Shutdown方法释放连接 socketTcp.Shutdown(SocketShutdown.Both); // 5. 关闭套接字 socketTcp.Close(); Console.WriteLine("客户端已关闭,按任意键退出"); Console.ReadKey(); } } }
首先运行服务端然后再运行客户端,服务端先发送一个消息Welcome to Connect to Server!,然后客户端接收消息打印,紧接着发送Hello i’m client!随后关闭,服务端在接收到客户端消息后打印,随后关闭,整个流程是一次性的。
问题
在主线程中会经历以下卡顿阶段:
1. 服务端Accept卡顿,这是由于服务端在一直等待客户端连接,直到客户端连上才能继续执行
2.Receive接收消息卡顿,一般由于网络情况所导致
当然还有收发消息不可控,服务端只能连接一个客户端的局限性
要解决以上问题,需要引入多线程的知识,在下一节将用多线程解决这几个问题
评论(0)
暂无评论