求一份unity中Socket-TCP从服务器接收数据方法的代码

求一份unity中Socket-TCP从服务器接收数据方法的代码,第1张

接收的字节使用了protubuf反序列化,处理的时候要注意和服务器发送消息类型、大小定义一致。如果不需要可以直接删除,用服务器发送字符串也是一样

using System.Collections

using System.Collections.Generic

using UnityEngine

using System.Net.Sockets

using System

using UnityEngine.Networking

using System.Text

using Google.Protobuf

using Pb

using System.Net

using System.IO

namespace Net

{

public class SocketClient

{

#region Public Variables

public static SocketClient Instance { getprivate set}

[Header("Network")]

public string ipAdress = "127.0.0.1"

public int port = 8000

public float waitingMessagesFrequency = 1

public bool loggedIn { getprivate set}

public bool FullLog = true

#endregion

#region Private m_Variables

private TcpClient m_Client

private NetworkStream m_NetStream = null

private byte[] m_Buffer = new byte[2048]

private NetworkStream m_OutStream

[Tooltip("This value should be >= to Server waitingMessagesFrequency")]

[Min(0)] private float m_DelayedCloseTime = 0.5f

#endregion

#region Delegate Variables

protected Action OnClientStarted = null //Delegate triggered when client start

protected Action OnClientClosed = null//Delegate triggered when client close

#endregion

private void Awake()

{

if (Instance == null)

Instance = this

}

//Start client and stablish connection with server

public void StartClient()

{

//Early out

if (m_Client != null)

{

ClientLogError($"There is already a runing client on {ipAdress}::{port}")

return

}

try

{

//Create new client

m_Client = new TcpClient()

//Set and enable client

m_Client.BeginConnect(ipAdress, port, new AsyncCallback(OnConnect), null)

ClientLogInfo($"Client Started on {ipAdress}::{port}")

OnClientStarted?.Invoke()

}

catch (SocketException)

{

ClientLogError("Socket Exception: Start Server first")

OnClose()

}

}

private void OnConnect(IAsyncResult asr)

{

ClientLogInfo("Connect Sucessful.")

m_NetStream = m_Client.GetStream()

m_Client.GetStream().BeginRead(m_Buffer, 0, m_Buffer.Length, new AsyncCallback(OnRead), m_Client)

}

#region Receive Message

private void OnRead(IAsyncResult result)

{

OnReceivedMessage(m_Buffer)

NetworkStream stream = m_Client.GetStream()

lock (stream)

{

Array.Clear(m_Buffer, 0, m_Buffer.Length)

m_Client.GetStream().BeginRead(m_Buffer, 0, m_Buffer.Length, new AsyncCallback(OnRead), m_Client)

}

}

private void OnReceivedMessage(byte[] bytes)

{

ByteBuffer buffer = new ByteBuffer(bytes)

OnRecieveMessageDeal(buffer, 0)

}

private void OnRecieveMessageDeal(ByteBuffer buffer, ushort length = 0)

{

// 判断传参length是否为0,如果不为0则代表非首次调用,不再取length值而使用传递的length

ushort nextLength

if(length != 0)

{

nextLength = length

}

else

{// 判断传参length是否为0,如果为0则为首次调用,直接取出length后进行处理

nextLength = buffer.ReadUInt16()

}

uint pId = buffer.ReadUInt32()

ClientLogInfo("Length:" + nextLength + ".id:" + pId)

byte[] bytes = buffer.ReadBytes(nextLength)

NetLogic(pId, bytes)

// 取出下一个length,如果为0则没有数据了,不为0则递归调用,并且传递已经取出的长度值

nextLength = buffer.ReadUInt16()

if (nextLength != 0)

{

OnRecieveMessageDeal(buffer, nextLength)

}

}

#endregion

#region Process

private void NetLogic(uint pid, byte[] bytes)

{

ClientLogInfo("Get Msg Id :" + pid)

if (pid == 1)

{

SyncPid syncPid = SyncPid.Parser.ParseFrom(bytes)

ClientLogInfo("sync pid:"+syncPid.Pid)

}

if (pid == 200)

{

BroadCast broadCast = BroadCast.Parser.ParseFrom(bytes)

ClientLogInfo("broadCast-pid:" + broadCast.Pid)

ClientLogInfo("broadCast-Tp:" + broadCast.Tp)

ClientLogInfo("broadCast-Position-x:" + broadCast.P.X)

ClientLogInfo("broadCast-Position-y:" + broadCast.P.Y)

ClientLogInfo("broadCast-Position-z:" + broadCast.P.Z)

ClientLogInfo("broadCast-Position-v:" + broadCast.P.V)

}

}

#endregion

#region Send Message

private void WriteMessage(byte[] message)

{

MemoryStream memoryStream2

MemoryStream memoryStream = memoryStream2 = new MemoryStream()

try

{

memoryStream.Position = 0L

BinaryWriter binaryWriter = new BinaryWriter(memoryStream)

ushort num = (ushort)message.Length

binaryWriter.Write(message)

binaryWriter.Flush()

if (m_Client != null &&this.m_Client.Connected)

{

byte[] array = memoryStream.ToArray()

m_OutStream.BeginWrite(array, 0, array.Length, new AsyncCallback(OnWrite), null)

}

else

{

ClientLogError("client.connected----->>false")

}

}

finally

{

if (memoryStream2 != null)

{

((IDisposable)memoryStream2).Dispose()

}

}

}

private void OnWrite(IAsyncResult r)

{

try

{

m_OutStream.EndWrite(r)

}

catch (Exception ex)

{

ClientLogError("OnWrite--->>>" + ex.Message)

}

}

public void SendMessage(ByteBuffer buffer)

{

this.SessionSend(buffer.ToBytes())

buffer.Close()

}

private void SessionSend(byte[] bytes)

{

this.WriteMessage(bytes)

}

#endregion

#region Close Client

//Close client connection

public void Close()

{

if (m_Client != null)

{

if (m_Client.Connected)

{

m_Client.Close()

}

m_Client = null

}

loggedIn = false

}

public void OnClose()

{

ClientLogError("Client Closed")

//Reset everything to defaults

if (m_Client.Connected)

m_Client.Close()

if (m_Client != null)

m_Client = null

OnClientClosed?.Invoke()

}

#endregion

#region ClientLog

// Custom Client Log With Text Color

public void ClientLogInfo(string msg)

{

if (FullLog)

{

Debug.Log($"<color=green>Client:</color>{msg}")

}

}

public void ClientLogWarning(string msg)

{

if (FullLog)

{

Debug.LogWarning($"<color=yellow>Client:</color>{msg}")

}

}

public void ClientLogError(string msg)

{

if (FullLog)

{

Debug.LogError($"<color=red>Client:</color>{msg}")

}

}

//Custom Client Log Without Text Color

public void ClientLog(string msg)

{

if (FullLog)

{

Debug.Log($"Client:{msg}")

}

}

#endregion

}

}

在服务端启动socket监听程序,客户端去连服务器的IP地址就行了!

举例(手写伪代码) :

在服务器端

Socket sock=new Socket("8080")

while(true){

data = sock.getInputStream();

//data 转成String型的数据str

if("msg"。equals(str)){

//todo....

}

}

在客户端

public static void main(String[] args) {

Socket sock = new Socket("服务器IP", "8080")

BufferedOutputStream out = new BufferedOutputStream(sock.getOutputStream())

out.write("msg".getBytes())

out.flush()

}

之前写过这样的一个小程序,我发布在自己的博客上:http://www.zhouhaibing.com/blog/archive/8

Server.c

#include <WinSock2.h>

#include <WS2tcpip.h>

#include <cstdio>

#include <iostream>

// for file read

#include <fstream>

#include <string>

int main() {

/* load the initializer library */

WSADATA wsaData

WSAStartup(MAKEWORD(2, 2), &wsaData)

/* list the each fields of wsaData */

// printf("wVersion: %d\n", wsaData.wVersion) // 514

// printf("wHighVersion: %d\n", wsaData.wHighVersion) // 514

// printf("iMaxSockets: %d\n", wsaData.iMaxSockets) // 0

// printf("iMaxUdpDg: %d\n", wsaData.iMaxUdpDg) // 0

/* you may not print the lpVendorInfo */

// printf("szDescription: %s\n", wsaData.szDescription) // WinSock 2.0

// printf("szSystemStatus: %s\n", wsaData.szSystemStatus) // Running

/* create socket(address family, type, protocol) */

int socket_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)

/* initialize the addrinfo hints */

struct addrinfo hints

memset(&hints, 0, sizeof(hints))

hints.ai_family = AF_INET

hints.ai_socktype = SOCK_STREAM

hints.ai_protocol = IPPROTO_TCP

hints.ai_flags = AI_PASSIVE

struct addrinfo *result = nullptr

/* by hints, and then get the result(a linked list, see fields below) */

getaddrinfo(NULL, "8080", &hints, &result)

/* the member fiekds of result */

// printf("ai_family: %d\n", result->ai_family) // 2

// printf("ai_socktype: %d\n", result->ai_socktype) // 1

// printf("ai_protocol: %d\n", result->ai_protocol) // 6

// printf("ai_flags: %d\n", result->ai_flags) // 0

// printf("ai_canonname: %s\n", result->ai_canonname) // (null)

// printf("ai_a ddrlen: %d\n", result->ai_addrlen) // 16

// printf("ai_addr->sa_family: %d\n", result->ai_addr->sa_family) // 2

// printf("ai_addr->sa_data: %s\n", result->ai_addr->sa_data) // 

// printf("ai_next: %x\n", result->ai_next) // 0

/* bind the socket to a address */

/* bind(socket, sockaddr name, name len) */

bind(socket_fd, result->ai_addr, result->ai_addrlen)

freeaddrinfo(result)

/* listen the socket */

/* listen(socket, backlog) */

listen(socket_fd, SOMAXCONN) /* 0x7fffffff */

while(true) {

/* accept a connection */

/* accept(socket, addr, addrlen) */

int client_fd = accept(socket_fd, nullptr, 0)

printf("New Connection Eastablished...\n")

/* Now we send the source code of this file to client */

std::ifstream fin("c:\\source.cpp")

/* store it into a buffer. */

while (fin.good()) {

// I rememeber there is a method called getline

std::string s

getline(fin, s)

// we need a new line

s = s + '\n'

send(client_fd, s.c_str(), s.size(), 0)

}

fin.close()

/* close client socket */

closesocket(client_fd)

}

/* may be never invoked */

closesocket(socket_fd)

WSACleanup()

return 0

}

Client.c

#include <WinSock2.h>

#include <cstdio>

#include <iostream>

#include <fstream>

int main() {

/* load the initializer library */

WSADATA wsaData

WSAStartup(MAKEWORD(2, 2), &wsaData)

/* create socket */

int socket_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)

/* connect */

sockaddr_in addr

addr.sin_family = AF_INET

addr.sin_addr.s_addr = inet_addr("127.0.0.1")

addr.sin_port = htons(8080)

/* connect(socket, sockaddr, namelen) */

connect(socket_fd, (sockaddr*)&addr, sizeof(addr))

/* buffer memory */

char buf[1024]

/* open a file for write */

std::ofstream fout("source.cpp", std::ios_base::trunc)

while (true) {

int read = recv(socket_fd, buf, 1024, 0) 

if (read == 0) {

fout.close()

printf("Connection Closed...\n")

break

}

if (read > 1024) {

printf("Buffer Overflow...\n")

} else {

buf[read - 1] = 0

/* now we can print the bytes from server */

fout << buf << std::endl

}

}

/* close socket */

closesocket(socket_fd)

WSACleanup()

return 0

}


欢迎分享,转载请注明来源:夏雨云

原文地址:https://www.xiayuyun.com/zonghe/264308.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-17
下一篇2023-04-17

发表评论

登录后才能评论

评论列表(0条)

    保存