C#⽹络通信Socket详解
最近在做⼀个联机的双⼈对战⽹络游戏,看教程之后对于Socket仍然⼀知半解,查完资料之后,就明⽩了,分享给⼤家,有错误欢迎指出,留⾔讨论。
⼀、准备
协议分为TCP和UDP。
TCP:传输控制协议
TCP是⾯向连接的、可靠的
TCP是基于字节流的传输层协议
UDP:⽤户数据报协议
UDP与TCP相反,是⽆连接的、不可靠的协议
UDP是基于数据报的传输(因其不可靠传输效率⽐TCP⾼)
我们采⽤TCP来实现B-S通信。
如上图,⼀次完整的Socket连接的流程,其中Socket是指套接字,套接字是⽀持TCP/IP协议⽹络通信的基本单元。
1. 开启⼀个连接之前,建⽴Socket连接
socket通信报文格式2. Bind使Socket与⼀个本地终结结点相关联,就是绑定IP和端⼝号
3. Listen开始监听,参数是监听⼏个客户端,0是不受限制。
主线程和线程池:⾮主线程不能设置Unity3d的组件
当客户端使⽤BeginReceive实现异步接收的时候,因为C#使⽤线程池处理异步调⽤,所以ReceiveCb并不在主线程中,所以采⽤中介者模式来调⽤,只有主线程能设置(Satrt() Update()属性主线程)UI组件,所以在ReceiveCb⽅法中只设置传递的字符,具体在主线程⾥云处理。
⾮主线程⽆法设置unity中的组件:
多线程转换成单线程,由于C#中的异步通信由线程池实现,BeginReceive属于多线程,所以需要通过中介在主线程之中处理消息。
服务器端
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace Servece
{
class Program
{
static void Main(string[] args)
{
//搭建 Socket
Socket serverSocket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
IPAddress ip = IPAddress.Parse("192.168.1.14");
IPEndPoint ipPoint = new IPEndPoint(ip, 1234);
//Bind
serverSocket.Bind(ipPoint);//建⽴连接
//Listen
serverSocket.Listen(0);//监听
//Socket clientSocket = serverSocket.Accept(); 只能接收⼀个客户端
//Accept
serverSocket.BeginAccept(AcceptCall, serverSocket);
Console.ReadKey();//很重要,不然会报错。作⽤:等待键盘输⼊,退出程序,使调试时能看到输出结果。如果没有此句,命令窗⼝会⼀闪⽽过。
}
static void AcceptCall(IAsyncResult ar) {
Socket severSocket = ar.AsyncState as Socket;
//给客户端发送信息
Socket clientSocket =severSocket.EndAccept(ar);
string msg = "你已连上服务器";
byte[] data = Encoding.UTF8.GetBytes(msg);
clientSocket.Send(data);
//接收客户端发来的信息
dataBuffer = new byte[1024];
clientSocket.BeginReceive(dataBuffer, 0, 1024, SocketFlags.None, ReciveClient, clientSocket); severSocket.BeginAccept(AcceptCall, severSocket);
}
static byte[] dataBuffer=new byte[1024];
static void ReciveClient(IAsyncResult ar)
{
Socket clientSocket = null;
//⽤try来处理客户端突然关闭的情况
try
{
clientSocket = ar.AsyncState as Socket;
int count = clientSocket.EndReceive(ar);
//当没有传过来信息的时候,关闭客户端
if (count == 0) {
clientSocket.Close();
return;
}
string msg = Encoding.UTF8.GetString(dataBuffer, 0, count);
Console.WriteLine("从客户端接收到消息:" + msg);
clientSocket.BeginReceive(dataBuffer, 0, 1024, SocketFlags.None, ReciveClient, clientSocket); }
catch (Exception e)
{
clientSocket.Close();
Console.WriteLine(e);
}
}
}
}
Socket serverSocket = new
Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
AdddressFamily:
InterNetwork使⽤IPv4
InterNetworkV6使⽤IPv6
SocketType
Stream字节流(⽀持可靠、双向、基于连接的字
节流)
Dgram⽀持数据报、⽆连接、不可靠的数据报类
型。
BeginReceive参数说明buffer Byte类型的数组,⽤于存储接收到的数据
offset buffer参数中存储数据的位置,该位置从零开始计数
size最⼤字节数
socketFlags SocketFlags值的按位组合,这⾥设置为0
callback回调函数,⼀个AsyncCallback委托
state ⼀个⽤户定义对象,其中包含接收操作的相关信息,当操作完成时,该对象会传递给EndReceive委托
Accept:
当开始监听之后,服务器调⽤Accept(0接收客户端的连接,若没有客户端连接,将会调⽤阻塞⽅法,也就是当没有客户端连接的时候,程序卡在Accept()不会往下执⾏,直到接收到客户端的连接。返回值是⼀个client(新客户端的Socket) 。
Receive:
阻塞⽅法,和Accept⼀样,参数为byte[]类型存储接收的数据,返回值为接收到数据的长度。
Send:
接受⼀个byte[]类型的参数指明要发送的内容。返回值指明发送数据的长度,服务器将字符串转换成byte[]类型发送给客户端
异步Socket:实现多个客户端。
BeginAccept
参数说明
asyncCallBack回调函数
state表⽰状态信息,必须保证state中包含
socket句柄
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论