zoukankan      html  css  js  c++  java
  • C#网络通信Socket详解

      最近在做一个联机的双人对战网络游戏,看教程之后对于Socket仍然一知半解,查完资料之后,就明白了,分享给大家,有错误欢迎指出,留言讨论。

    一、准备  

    协议分为TCP和UDP。

    TCP:传输控制协议

    • TCP是面向连接的、可靠的
    • TCP是基于字节流的传输层协议

    UDP:用户数据报协议

    • UDP与TCP相反,是无连接的、不可靠的协议
    • UDP是基于数据报的传输(因其不可靠传输效率比TCP高) 

    我们采用TCP来实现B-S通信。

    如上图,一次完整的Socket连接的流程,其中Socket是指套接字,套接字是支持TCP/IP协议网络通信的基本单元。

    1. 开启一个连接之前,建立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句柄

  • 相关阅读:
    node.js之Cookie
    jQuery和js之Cookie实现
    StringRedisTemplate操作Redis
    Could not get a resource from the pool 错误解决
    tableLayoutPanel 列宽度设置
    KRBTabControl(中文)Windows选项卡控件
    KRBTabControl
    Deferred content load was not performed. To provide the content, subscribe to the View's QueryControl event
    where(泛型类型约束)
    ExportAsFixedFormat Visio文件另存为其他几种格式的处理
  • 原文地址:https://www.cnblogs.com/shuanglu/p/8528209.html
Copyright © 2011-2022 走看看