unity客戶端與c++服務器之間的簡單通訊_1


// 服務器

# pragma once
using namespace std;
# include <iostream>
# include <string>
# include <stdio.h>
# include <winsock2.h>
# pragma comment(lib,”ws2_32.lib”)

# include “Tool.h”

void main()
{
WSAData    wsadata;
SOCKET    ListeningSocket;
SOCKET    newConnection;

sockaddr_in serverAddr;
sockaddr_in clientAddr;

//    Struct sockaddr_in
//    {
//    short    sin_family;     Sin_family:代表協議族,一般為AF_INET.代表使用TCP/IP協議族
//    u_short    sin_port;    Sin_port: 代表端口號16位。注意字節序
//    struct in_addr    sin_addr;    Sin_addr:代表32位IPV4地址。
//    char    sin_zero[8];    Sin_zero:8個字節的0補充。
//    }

int    clientAddrLen = sizeof(sockaddr_in);
int    port = 5150;
int    ret;
char    dataBuffer[1024];

//    int WSAStartup(WORD version, LPWSADATA lpWSAData);

/*    此函數在應用程序中初始化Windows Sockets DLL ,只有此函數調用成功后,應用程序才可以再調用其他Windows Sockets DLL中的API函數。如果成功返回0。
Version 代表程序需要的Winsock的最高版本。其中主版本號在低
字節,次版本號在高字節。
比如:使用1.2的版本, version的值0x0201。

也可以使用MAKEWORD(2, 2)。
WORD MAKEWORD
(
BYTE bLow,
BYTE bHigh
);

lpWSAData 代表WSADATA的指針,里面包括本機系統的信息。它是返回值
struct WSAData 
{
WORD wVersion;    代表建議使用的版本號
WORD wHighVersion;           代表系統最高支持的版本號
char szDescription[WSADESCRIPTION_LEN + 1];
char szSystemStatus[WSASYSSTATUS_LEN + 1];
unsigned short iMaxSockets;
unsigned short iMaxUdpDg;
char FAR * lpVendorInfo;
};
*/

if ((ret = WSAStartup(MAKEWORD(2, 2), &wsadata)) != 0)
{
cout << “WSAStart up is failed with error\t” << ret << endl;
return;
}

/*    SOCKET socket(int af, int type, int protocol)
af:代表協議族,一般為AF_INET.
Type : 代表套接口類型,SOCK_STREAM流套接字, SOCK_DGRAM數據報套接字

流套接字上數據進出是無邊界的,可靠的。
數據報套接字是有邊界的,不可靠的(相對於流套接字而言)
流套接字是速度慢,數據報套字速度快。
流套接字是有序的,數據報套接字是無序的(后發的數據有可能先被接收到。)

所以一般tcp 用劉套接字,udp用數據報   關於udp協議,后章會給出(好吧,可能會給出,看有沒有時間)
估計qq的消息用得是udp,具體沒去研究—-

Protocol : 指定所用的協議.如:IPPROTO_TCP、PPROTO_UDP  
返回值:如果沒有錯誤發生,返回一個新的套接字,
否則返回INVALID_SOCKET。
*/

// 創建一個監聽套接字,所謂監聽,就是看看有沒有客戶端連接上來
if (INVALID_SOCKET == (ListeningSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)))
{
cout << “socket is falied with error\t” << WSAGetLastError() << endl;
WSACleanup();
return;
}

//    本機系統所用的字節序稱為:本機字節順序
//    網絡標准使用的字節序稱為:網絡字節順序

/*    htons()——本機到網絡(short)
htonl()——本機到網絡(Long)
ntohs()——網絡到本機(short)
ntohl()——網絡到本機(long)
*/

serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(port);
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
//INADDR_ANY就是指定地址為0.0.0.0的地址,這個地址事實上表示不確定地址,或“所有地址”、“任意地址”。 一般來說,在各個系統中均定義成為0值。

//    綁定端口
//    bind(SOCKET s, const struct sockaddr FAR *name, int namelen);

//    接下來要為服務器端定義的這個監聽的socket指定一個地
//    及端口(Port),這樣客戶端才知道待會要連接哪一個地址的哪個
//    端口,為此我們要調用bind()函數,該函數調用成功返回0,否則
//    返回SOCKET_ERROR

if (SOCKET_ERROR == bind(ListeningSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)))
{
cout << “bind is falied with error\t” << WSAGetLastError() << endl;
closesocket(ListeningSocket);
WSACleanup();
return;
}

//    監聽
//    int  listen( SOCKET s, int backlog );

//    服務器端的socket對象綁定完成之后,服務器端必須建立一個監聽的隊列來接收客戶端的連接請求。
//    listen()函數使服務器端的socket 進入監聽狀態,並設定可以建立的最大連接數(目前最大值限制為 5, 最小值為1)。
//    該函數調用成功返回0,否則返回SOCKET_ERROR。

if (SOCKET_ERROR == listen(ListeningSocket, 5))
{
cout << “listen is falied with error\t” << WSAGetLastError() << endl;
closesocket(ListeningSocket);
WSACleanup();
return;
}

cout << “now we are waiting a connection from client” << endl;

cout <<“sizeof sockaddr_in:\t”<< sizeof(sockaddr_in) << “\tsizeof sockaddr\t” << sizeof(sockaddr) << endl;

//    服務器端接受客戶端的連接請求
//    SOCKET  accept( SCOKET s, struct sockaddr FAR *addr,int FAR *addrlen );
//    為了使服務器端接受客戶端的連接請求,就要使用accept() 函數,
//    該函數新建一個socket與客戶端的socket相通,原先監聽之socket繼續進入監聽狀態,
//    等待他人的連接要求。該函數調用成功返回一個新產生的socket對象,否則返回INVALID_SOCKET。
if (INVALID_SOCKET == (newConnection = accept(ListeningSocket, (sockaddr*)&clientAddr, &clientAddrLen)))
{
cout << “accept is falied with error\t” << WSAGetLastError() << endl;
closesocket(ListeningSocket);
WSACleanup();
return;
}

cout << “get a connect from client addr\t” << inet_ntoa(clientAddr.sin_addr) << “\t” << ntohs(clientAddr.sin_port) << endl;

//    數據的接收
//    int recv( SOCKET s, char FAR *buf, int len, int flags );

//    參數:
//    s為socket 的識別碼 
//    buf:存放接收到的信息的暫存區 
//    len:buf的長度 
//    flags:此函數被調用的方式
//    返回值就是接受的字符串的長度(在沒出錯的情況下)

if (SOCKET_ERROR == (ret =  recv(newConnection, dataBuffer, sizeof(dataBuffer), 0)))
{
cout << “recv is errow with\t” << WSAGetLastError() << endl;
closesocket(newConnection);
WSACleanup();
return;
}

dataBuffer[ret] = ‘\0’;

//wchar_t *temp = Tool::getSingleTon()->charToWchar(dataBuffer);

//cout << “ret:\t” << ret << “\tdata\t” << temp << endl;

//  暫時不知道怎么解析unity客戶端發過來的中文,,,憂傷的不行,試了好幾種方法,有知道的可以告訴我下

cout << dataBuffer << endl;

//    結束 socket 連接

//    結束服務器和客戶端的通信連接是很簡單的,這一過程可以由服務器或客戶機的任一端啟動,
//    只要調用closesocket()就可以了,而要關閉Server端監聽狀態的socket,同樣也是利用此函數。
//    另外,與程序啟動時調用WSAStartup()憨數相對應,程式結束前,需要調用 WSACleanup()
//    來通知Winsock Stack釋放socket所占用的資源。這兩個函數都是調用成功返回0,否則返回SOCKET_ERROR。

//    int PASCAL FAR closesocket(SOCKET s);
//    參 數:s為socket 的識別碼;
//    int PASCAL FAR WSACleanup(void);

closesocket(newConnection);

WSACleanup();
}

 

 

unity客戶端

using UnityEngine;
using System.Collections;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;

public class TestScoket : MonoBehaviour
{

    void Start()
    {
        ConncetServer();
    }

    void ConncetServer()
    {
        IPAddress ipAdr = IPAddress.Parse(“10.0.0.22”);

        IPEndPoint ipEp = new IPEndPoint(ipAdr, 5150);

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

        clientScoket.Connect(ipEp);

        string output = “zhangsan”;//  中文暫時不知道怎么解析  “中文”

        byte[] concent = Encoding.UTF8.GetBytes(output);

        //byte[] concent = Encoding.Unicode.GetBytes(output);
        int count = clientScoket.Send(concent);

        Debug.LogError(count);

        //byte[] response = new byte[1024];

        //int bytesRead = clientScoket.Receive(response);

        //string input = Encoding.UTF8.GetString(response, 0, bytesRead);

        //print(“Client request:” + input);
        clientScoket.Shutdown(SocketShutdown.Both);
        clientScoket.Close();
    }

    private void ConnectCallBack(System.IAsyncResult ar)
    {
        Debug.LogError(“連接成功”);
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM