一个简单的UDP程序—C++服务器和C# .NET客户端。用Unity开发网络游戏除了使用Unity自带的Network类之外,比较原始的方法就是使用Socket接口了。本文基于.NET平台的Socket接口,编写了一个UDP协议下的简单程序,实现了类似于Echo的功能。具体为客户端向服务器发送一个信息,服务器返回一个应答。代码如下:
C++编写的服务器端(使用Winsock):
#include
#include
#pragma comment(lib, "ws2_32.lib") using namespace std; #define DEF_PORT 1234 #define BUF_SIZE 64 int main(int argc, char* argv[]) { WSADATA wsaData; SOCKET srvSock = 0;//服务器socket句柄 sockaddr_in srvAddr,//服务器端地址 clntAddr;//客户端地址 unsigned short port = DEF_PORT;//端口号 int result,//返回结果 addrLen = sizeof(srvAddr);//地址长度 char recvBuf[BUF_SIZE];//服务器接收端缓冲区 char answer[] = "Hello,I'm simplatform server!"; //应答 //初始化套接字 WORD socketVersion = MAKEWORD(2, 2); if (WSAStartup(socketVersion, &wsaData) != 0) { printf("初始化套接字失败!"); return 0; } //创建套接字 srvSock = socket(AF_INET, SOCK_DGRAM, 0); if (srvSock == INVALID_SOCKET) { printf("Socket error!"); return 0; } //为socket绑定一个本地地址 srvAddr.sin_family = AF_INET; srvAddr.sin_port = htons(port); srvAddr.sin_addr.S_un.S_addr = INADDR_ANY; result = bind(srvSock, (sockaddr*)&srvAddr, addrLen); if (result == SOCKET_ERROR) { printf("Bind error!"); closesocket(srvSock); return 0; } printf("[Simplatform Server] 服务器正在运行...\n"); //主循环 while (1) { result = recvfrom(srvSock, recvBuf, BUF_SIZE, 0, (sockaddr*)&clntAddr, &addrLen); if (result > 0) { recvBuf[result] = 0; printf("[Simplatform Server] recv: \"%s\", from %s\r\n", recvBuf, inet_ntoa(clntAddr.sin_addr)); //应答 sendto(srvSock, answer, strlen(answer), 0, (sockaddr*)&clntAddr, addrLen); } } closesocket(srvSock); WSACleanup(); return 0; }
C# .NET客户端:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
namespace simClient
{
class Program
{
static void Main(string[] args)
{
const int DEF_SIZE = 64;
const string srvIp = "127.0.0.1"; //服务器IP地址
Socket clntSock = new Socket(AddressFamily.InterNetwork,
SocketType.Dgram, ProtocolType.Udp); //创建socket
IPAddress srvAddr = IPAddress.Parse(srvIp); //服务器IP地址
IPEndPoint srvIpEnd = new IPEndPoint(srvAddr, 1234); //服务器地址
EndPoint srvEnd = (EndPoint)srvIpEnd; //必须要经过这个类型转换,EndPoint是一个抽象类
byte[] msg = Encoding.ASCII.GetBytes("Hello!"); //发送消息
byte[] recvBuf = new byte[DEF_SIZE]; //接收缓冲区大小
int result = 0; //接收的字节数
while (true)
{
clntSock.SendTo(msg, srvEnd);
try
{
result = clntSock.ReceiveFrom(recvBuf, ref srvEnd);
}
catch (SocketException e)
{
Console.WriteLine("服务器未启动!");
System.Threading.Thread.Sleep(4000); //4s后重新发送请求
continue;
}
if (result > 0)
{
//控制台输出byte[]数组必须要经过转换。
string strResult = System.Text.Encoding.ASCII.GetString(recvBuf);
Console.WriteLine("收到应答:{0}", strResult);
}
System.Threading.Thread.Sleep(2000); //每隔2s发送一次
}
clntSock.Close();
}
}
}
运行结果:
另附:C++版本的客户端代码
#include
#include
#pragma comment(lib, "ws2_32.lib") using namespace std; #define DEF_PORT 1234 #define BUF_SIZE 64 int main(int argc, char* argv[]) { WSADATA wsaData; SOCKET clntSock = 0;//客户端SOCKET sockaddr_in srvAddr,//服务器端地址 fromAddr;//存储发送端的地址 char