一个简单的UDP程序—C++服务器和C# .NET客户端

来源:互联网 发布:知茵是否有网上旗舰店 编辑:程序博客网 时间:2024/06/05 11:23

用Unity开发网络游戏除了使用Unity自带的Network类之外,比较原始的方法就是使用Socket接口了。本文基于.NET平台的Socket接口,编写了一个UDP协议下的简单程序,实现了类似于Echo的功能。具体为客户端向服务器发送一个信息,服务器返回一个应答。代码如下:

C++编写的服务器端(使用Winsock):

#include <stdio.h>#include <WinSock2.h>#pragma comment(lib, "ws2_32.lib") using namespace std;#define DEF_PORT 1234#define BUF_SIZE 64int 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 <WinSock2.h>#include <stdio.h>#pragma comment(lib, "ws2_32.lib")using namespace std;#define DEF_PORT 1234#define BUF_SIZE 64int main(int argc, char* argv[]){WSADATA wsaData;SOCKET clntSock = 0;//客户端SOCKETsockaddr_in srvAddr,//服务器端地址 fromAddr;//存储发送端的地址char *dest = "127.0.0.1", //服务器IP地址*sendData = "Hello!";//发送数据char recvBuf[BUF_SIZE];//接收缓冲区int result, addrLen = sizeof(srvAddr);//接收命令行参数if (argc == 2) {dest = argv[1];}//初始化套接字WORD socketVersion = MAKEWORD(2, 2);if (WSAStartup(socketVersion, &wsaData) != 0) {printf("初始化失败!");return 0;}//创建socketclntSock = socket(AF_INET, SOCK_DGRAM, 0);if (clntSock == INVALID_SOCKET) {printf("socket error!");return 0;}//设置服务器地址srvAddr.sin_family = AF_INET;srvAddr.sin_addr.S_un.S_addr = inet_addr(dest);srvAddr.sin_port = htons(DEF_PORT);if (srvAddr.sin_addr.S_un.S_addr == INADDR_NONE) {printf("Invalid Address!\r\n");return 0;}while (1){sendto(clntSock, sendData, strlen(sendData), 0, (sockaddr*)&srvAddr, addrLen);result = recvfrom(clntSock, recvBuf, BUF_SIZE, 0, (sockaddr*)&fromAddr, &addrLen);if (result > 0) {recvBuf[result] = 0;printf("[Simplatform Client] recv: \"%s\", from %s\r\n",recvBuf, inet_ntoa(fromAddr.sin_addr));}Sleep(2000);}closesocket(clntSock);WSACleanup();return 0;}

参考文献:

1. 《Winsock网络编程经络》

2. MSDN:https://msdn.microsoft.com/zh-cn/library/system.net.sockets(v=vs.110).aspx

0 0
原创粉丝点击