Socket 基础&实例(上)

Socket 基础知识

  1. TCP/IP层次模型

    a. 应用层
    b. 传输层 : UDP和TCP(区别即 TCP传输控制协议,是一种提供可靠数据传输的通用协议。
         UDP是一个面 向无连接的协议,此处可能解释不太清楚,百度哈。(~ o ~)~zZ)
    c. 网络层:通信子网,它通过网络连接交换传输层发出的实体数据。
    d. 链路层:是建立在物理传输能力的基础上,以帧为单位传输数据,
         它的主要任务就是进行数据封装和数据链接的建立

    TCP分节传输图解
    这里写图片描述
    (每层传输过程中,都将增加分节的头)

  2. Socket类型

    a. 流式Socket
     是一种面向连接的Socket,针对于面向连接的TCP服务应用,安全,但是效率低
    b. 数据报式Socket
     是一种无连接的Socket,对应于无连接的UDP服务应用,不安全,但效率高

     组图说明Socket客户端和服务器的连接过程
    这里写图片描述
    这就是所谓的三次握手,哈哈。。

  3. Socket常用类和方法

    相关类:

    IPAddress:包含了一个IP地址
    IPEndPoint:包含了一对IP地址和端口号

方法:

    Socket():创建一个Socket
    Bind():绑定一个本地的IP和端口号(IPEndPoint)
    Listen():让Socket侦听传入的连接吃那个病,并指定侦听队列容量
    Connect():初始化与另一个Socket的连接
    Accept():接收连接并返回一个新的Socket
    Send():输出数据到Socket
    Receive():从Socket中读取数据

上方法在Socket连接中基本上都会用到

  1. 实战部分代码

服务器代码(新建项目的时候,此处是
这里写图片描述

using System;
using System.Net;
using System.Collections.Generic;
using System.Net.Sockets;
using System.IO;
using System.Text;
using System.Threading;
using System.Runtime.Serialization.Formatters.Binary;

public class Echoserver
{
    private static int m_SocketCount = 0;

    private static ManualResetEvent m_ManualResetEvent = new ManualResetEvent(false);


    //entry point of main method.
    public static void Main()
    {
        IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 10068);

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

        try
        {
            serverSocket.Bind(ipEndPoint);
            serverSocket.Listen(20);
            Console.WriteLine("Server Start");
            while (true)
            {
                m_ManualResetEvent.Reset(); //将线程置于非终止状态,也就是等待当前线程完成;
                serverSocket.BeginAccept(new AsyncCallback(Accept), serverSocket);
                m_ManualResetEvent.WaitOne(); //阻塞主线程,这里的作用是不退出程序;
            }
        }
        catch (System.Exception ex)
        {
            Console.WriteLine("Exception" + ex);
        }
    }


    public static void Accept(IAsyncResult result)
    {
        m_ManualResetEvent.Set(); //通知主线程继续;

        Socket serverSocket = (Socket)result.AsyncState;


        Console.WriteLine("Accept one Client " + (++m_SocketCount));

        //已经Accept客户端之后就停止Accept;
        Socket receiverSocket = serverSocket.EndAccept(result);

        //开始Receive;
        StateObject state = new StateObject();
        state.m_CurSocket = receiverSocket;
        receiverSocket.BeginReceive(state.m_Buffer, 0, StateObject.m_BufferSize, 0, new AsyncCallback(ReceiveCallBack), state);
    }

    public static void ReceiveCallBack(IAsyncResult result)
    {
        String content = String.Empty;
        StateObject state = (StateObject)result.AsyncState;
        Socket receiverSocket = state.m_CurSocket;
        try
        {
            int byteRead = receiverSocket.EndReceive(result);

            if (byteRead > 0)
            {
                //获取数据长度;
                byte[] datalengtharr = new byte[4];
                Buffer.BlockCopy(state.m_Buffer, 0, datalengtharr, 0, 4);
                int datalength = BitConverter.ToInt32(datalengtharr, 0);
                Console.WriteLine("receive data length = " + datalength.ToString());

                //获取数据主体;
                byte[] dataarr = new byte[byteRead - 4];
                Buffer.BlockCopy(state.m_Buffer, 4, dataarr, 0, byteRead - 4);
                state.m_StringBuilder.Append(Encoding.ASCII.GetString(dataarr, 0, byteRead - 4));

                content = state.m_StringBuilder.ToString();

                //判断数据长度,是否接收完全;
                if (!(byteRead - 4 < datalength))
                {
                    Console.WriteLine("Receive " + content.Length + "  " + content);

                    //接收完全后发送数据给客户端;
                    Send(receiverSocket, "success from server");
                }
                else
                {
                    //数据没有接收完,继续接收;
                    receiverSocket.BeginReceive(state.m_Buffer, 0, StateObject.m_BufferSize, 0, new AsyncCallback(ReceiveCallBack), state);
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }

    }

    public static void Send(Socket handler, String data)
    {
        byte[] byteData = Encoding.ASCII.GetBytes(data);
        try
        {
            handler.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), handler);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }

    }

    public static void SendCallback(IAsyncResult result)
    {
        try
        {
            Socket handler = (Socket)result.AsyncState;
            int bytesSend = handler.EndSend(result);

            Console.WriteLine("Sent {0} bytes to client.", bytesSend);

            handler.Shutdown(SocketShutdown.Both);

            handler.Close();
        }
        catch (System.Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
    }

    public class StateObject
    {
        public Socket m_CurSocket = null;
        public const int m_BufferSize = 1024;
        public byte[] m_Buffer = new byte[m_BufferSize];
        public StringBuilder m_StringBuilder = new StringBuilder();
    }
}

客户端代码

using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Collections.Generic;
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;

public class Test : MonoBehaviour
{
    /// <summary>
    /// 连接到服务器
    /// </summary>
    public void AsynConnect()
    {
        //端口及IP
        IPEndPoint ipe = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 10068);
        //创建套接字
        Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        //开始连接到服务器
        client.BeginConnect(ipe, asyncResult =>
        {
            client.EndConnect(asyncResult);
            //向服务器发送消息
            DataMsg msg = new DataMsg();
            msg.indexPos = 5;
            msg.name = "宏宇";
            msg.sex = 1;
            List<string> otherPerList = new List<string>();
            otherPerList.Add("小鸭");
            otherPerList.Add("斗鸡");
            otherPerList.Add("斗鸟");
            msg.otherPerList.AddRange(otherPerList);

            //AsynSend(client, msg);
            AsynSend(client, "你好我是客户端");
            //AsynSend(client, "第一条消息");
            //AsynSend(client, "第二条消息");
            //接受消息
            AsynRecive(client);
        }, null);
    }

    /// <summary>
    /// 发送消息
    /// </summary>
    /// <param name="socket"></param>
    /// <param name="message"></param>
    public void AsynSend(Socket socket, string message)
    {
        if (socket == null || message == string.Empty) return;
        //编码
        byte[] data = Encoding.UTF8.GetBytes(message);
        try
        {
            socket.BeginSend(data, 0, data.Length, SocketFlags.None, asyncResult =>
            {
                //完成发送消息
                int length = socket.EndSend(asyncResult);
                Debug.Log(string.Format("客户端发送消息:{0}", message));
            }, null);
        }
        catch (Exception ex)
        {
            Debug.Log(string.Format("异常信息:{0}", ex.Message));
        }
    }

    public void AsynSend(Socket socket, DataMsg msgData)
    {
        if (socket == null || msgData == null)
        {
            return;
        }
        Debug.Log(msgData);
        MemoryStream mStream = new MemoryStream();
        //BinaryFormatter bFormatter = new BinaryFormatter();
        BinaryFormatter iFormatter = new BinaryFormatter();
        //bFormatter.Serialize(mStream, msgData);
        //bFormatter.Serialize(mStream, "fff");
        iFormatter.Serialize(mStream, msgData);
        mStream.Flush();
        byte[] buffer = new byte[1024];
        mStream.Position = 0;
        while (mStream.Read(buffer, 0, buffer.Length) > 0)
        {
            socket.Send(buffer);
        }
        socket.Close();
        Debug.Log("数据发送完毕");


    }

    /// <summary>
    /// 接收消息
    /// </summary>
    /// <param name="socket"></param>
    public void AsynRecive(Socket socket)
    {
        byte[] data = new byte[1024];
        try
        {
            //开始接收数据
            socket.BeginReceive(data, 0, data.Length, SocketFlags.None,
            asyncResult =>
            {
                int length = socket.EndReceive(asyncResult);
                Debug.Log(string.Format("收到服务器消息:{0}", Encoding.UTF8.GetString(data)));
                //AsynRecive(socket);
            }, null);
        }
        catch (Exception ex)
        {
            Debug.Log(string.Format("异常信息:", ex.Message));
        }
    }



    void Awake()
    {
        gameObject.GetComponent<Button>().onClick.AddListener(delegate()
        {
            OnClickEvent(gameObject);
        });
    }

    void OnClickEvent(GameObject target)
    {
        Debug.Log("Click" + target.name);
        AsynConnect();
    }

}

[Serializable]
public class DataMsg
{
    public int indexPos;
    public int sex;
    public string name;
    public List<string> otherPerList;
    public DataMsg()
    {
        indexPos = 0;
        sex = 0;
        name = string.Empty;
        otherPerList = new List<string>();
    }
}

大家可能也注意到了我这里的客户端,留有传序列化的数据的方法,没错,本次实验只做传输数据,字符串简单的数据,后面会涉及多终端对一个服务器时的数据传输,等等,一直研究下去

如果有错误的地方,请指点,比较晚了,不好的下次再更新

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值