UDP服务器—实现数据通信

目录

前言

1.接口介绍

2.编写服务器

3.编写客户端

4.测试

总结


前言

        在这篇文章中为大家介绍如何通过编码实现数据通信,实现思路是根据前面介绍的网络编程函数编写一个服务端和客户端,实现客户端和服务端双方通信

1.接口介绍

创建套接字

 #include <sys/types.h>         #include <sys/socket.h>int socket(int domain, int type, int protocol);

domain:网络通信采用AF_INET

type:提供的服务类型,包含TCP流式服务和UDP数据包服务

实现UDP服务器参数设置为SOCK_DGRAM

protocol:采用的协议,一般设置为0,前面的两个参数决定了第三个参数

创建套接字的本质是告诉操作系统要进行网络通信,然后由操作系统在底层维护一个文件缓冲区,创建成功返回该文件描述符,后续数据通信,上层选择将数据放到该文件缓冲区中或者从文件缓冲区中去读数据

返回值:打开的文件描述符

绑定端口号

  #include <sys/types.h>        #include <sys/socket.h>int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

sockfd : 创建套接字的返回值

struct sockaddr* addr:使用时填充该结构体的字段

a.协议字段

b.端口号

端口号在进行填充的时候需要先进行转换为网络字节序


#include <arpa/inet.h>uint16_t htons(uint16_t hostshort);

获取对方传输过来的端口号时需要将网络字节序转化为本机

#include <arpa/inet.h>uint16_t ntohs(uint16_t netshort);

c.IP地址

一般在服务器的实现中IP地址是不需要绑定的

在客户端中发送数据需要填充服务端的IP地址,因为在用户层IP地址是字符串类型,在网络上传输时IP地址是整型数据,所以需要进行转换

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>in_addr_t inet_addr(const char *cp);

需要获取对方网络中传输过来的IP地址需要将整型转换为字符串类型

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>char *inet_ntoa(struct in_addr in);

注:因为是网络通信,所以在填充好字段之后需要在传参的时候强转为sockaddr_in

addrlen:结构体的大小

接受数据

#include <sys/types.h>
#include <sys/socket.h>ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);

sockfd:文件描述符

buf:用户缓冲区

len:用户缓冲区的大小

flags:设置为0表示阻塞式调用

src_addr:输出型参数,用来获取对方的IP地址和port

addrlen:结构体的大小

发送数据

 #include <sys/types.h>#include <sys/socket.h>ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);

sockfd:文件描述符

buf:用户缓冲区

len:用户缓冲区的大小

flags:设置为0表示阻塞式调用

dest_addr:填充需要发送对端主机的信息,包含IP地址和port端口号

addrlen:结构体的大小

有了上面这些的这些接口,下面我们就可以正式编写一个客户端和一个服务端了

2.编写服务器

形成makefile

.PHONY:all
all:udpServer udpClientudpServer:udpServer.ccg++ -o $@ $^ -std=c++11
udpClient:udpClient.ccg++ -o $@ $^ -std=c++11.PHONY:clean
clean:rm -rf udpServer udpClient

编写服务器:udpServer.hpp

#pragma once
#include <iostream>
#include <string>
#include <strings.h>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <functional>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>namespace Server
{using namespace std;const static string defaultIP = "0.0.0.0";enum {USAGE_ERR = 1, SOCKET_ERR, BIND_ERR};class udpServer{public:udpServer(uint16_t port, const string &ip = defaultIP) :_port(port),_ip(ip),_sockfd(-1){}void initServer(){//1.创建socket_sockfd = socket(AF_INET,SOCK_DGRAM,0);if(_sockfd == -1){cerr<<"socket error:" << errno << strerror(errno) << endl;exit(SOCKET_ERR);}//2.绑定port和ipstruct sockaddr_in local;bzero(&local,sizeof(local));local.sin_family = AF_INET;local.sin_port = htons(_port);local.sin_addr.s_addr = htonl(INADDR_ANY);int n = bind(_sockfd,(struct sockaddr*)&local,sizeof(local));if(n == -1){cerr<<"bind error:" << errno << strerror(errno) << endl;exit(BIND_ERR);}}void startServer(){char buffer[1024];for(;;){struct sockaddr_in peer;socklen_t len = sizeof(peer);//peer len:输入,输出型参数:用来保存客户端的ip和portssize_t s = recvfrom(_sockfd,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&len);//打印发送来的数据if(s){buffer[s] = { 0 };//inet_ntoa:网络字节序->int  int->点分十进制string clientIp = inet_ntoa(peer.sin_addr);//ntohl:网络字节序->intuint16_t clientPort = ntohs(peer.sin_port);string message = buffer;cout << clientIp << "[" << clientPort << "]" << message << endl;}}}~udpServer(){}private:uint16_t _port;string _ip;int _sockfd;};
}

启动服务器:udpServer.cc

#include "udpServer.hpp"
#include <memory>
using namespace Server;
static void Usage(string proc)
{cout << "\nUsage:\n\t" << proc << " local_port\n\n";
}
int main(int argc, char *argv[])
{if (argc != 2){Usage(argv[0]);exit(USAGE_ERR);}uint16_t port = atoi(argv[1]);unique_ptr<udpServer> usvr(new udpServer(port));usvr->initServer();usvr->startServer();return 0;
}

3.编写客户端

编写客户端:udpClient.hpp

#pragma once
#include <iostream>
#include <string>
#include <strings.h>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <functional>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>namespace Client
{using namespace std;   class udpClient{public:udpClient(const string& serverIp,const uint16_t serverPort):_serverIp(serverIp),_serverPort(serverPort),_sockfd(-1) {}void initClient(){//1.创建socket_sockfd = socket(AF_INET,SOCK_DGRAM,0);if(_sockfd == -1){cerr<<"socket error:" << errno << strerror(errno) << endl;exit(2);}//client一定需要bind,服务器只有一个,但是客户端有许多个,所以服务端需要显示的绑定端口号//客户端一般不需要自己显示的绑定,而是由os自动形成端口号进行绑定}void run(){struct sockaddr_in server;memset(&server,0,sizeof(server));server.sin_family = AF_INET;server.sin_addr.s_addr = inet_addr(_serverIp.c_str());server.sin_port = htons(_serverPort);string message;while(1){cout << "请输入:";cin >> message;//发送数据到客户端sendto(_sockfd,message.c_str(),message.size(),0,(const struct sockaddr*)&server,sizeof(server));}}private:string _serverIp;int _sockfd;uint16_t _serverPort;};
}

启动客户端:udpClient.cc

#include"udpClient.hpp"
#include<memory>
using namespace Client;
static void Usage(string proc)
{cout << "\nUsage:\n\t" << proc << " server_ip server_port\n\n";
}
int main(int argc,char* argv[])
{if(argc != 3){Usage(argv[0]);exit(1);}string serverip = argv[1];uint16_t serverport = atoi(argv[2]);unique_ptr<udpClient> uct(new udpClient(serverip,serverport));uct->initClient();uct->run();return 0;
}

4.测试

说明:因为本次是在一台主机上,所以为了做测试将IP地址绑定为"127.0.0.1",该IP地址的特点是专门用来在本主机上做测试,称为本地环回,后续在不同主机上通信的时候只需要将IP地址改为对方主机的IP地址即可。

 此时我们就可以看到当客户端向服务器发送数据时,服务器收到了数据,并且将数据回显出来

总结

通过上面的编码,使用UDP协议简单实现了一个服务器,可以用来进行数据通信了,是不是感觉很神奇呀,看到这里你就会发现,原来网络通信也并不复杂,和系统内部进程间通信有异曲同工之妙关于网络通信的更多细节,后面再一一为大家介绍,我们下次再见!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/1382824.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

【TypeScript】this指向,this内置组件

this类型 TypeScript可推导的this类型函数中this默认类型对象中的函数中的this明确this指向 怎么指定this类型 this相关的内置工具类型转换ThisParameterType<>ThisParameterType<>ThisType TypeScript可推导的this类型 函数中this默认类型 对象中的函数中的this…

光遇android和ios有什么区别,光遇安卓和苹果可以一起玩吗?

01 首先经过测试&#xff0c;国际服的安卓和苹果是可以一起玩的&#xff0c;这两个平台的玩家可以相互添加好友&#xff0c;并且在地图中也可以看到各自的身影。既然国际服才用了互通的规则&#xff0c;那么国服自然也应该互通&#xff0c;但是受到系统兼容等问题的影响&#x…

ios的皇室战争怎么转android,皇室战争苹果怎么转安卓?小问题,让小编来告诉你...

皇室战争苹果怎么转安卓&#xff1f;小问题&#xff0c;让小编来告诉你 皇室战争安卓国服即将上线&#xff0c;许多玩家都满怀期待&#xff0c;不过也有一些疑问&#xff0c;就是皇室战争苹果可以转安卓吗&#xff1f;皇室战争苹果可以和安卓数据互通吗&#xff1f;看这里 皇室…

android转服务器吗,王者荣耀角色迁移iOS区可以转安卓区吗 王者荣耀角色迁移iOS区转安卓区详情...

王者荣耀角色迁移iOS区可以转安卓区吗?王者荣耀在王者营地中推出角色迁移功能&#xff0c;角色迁移上线后不少玩家都在问iOS区可以转安卓区的问题&#xff0c;下面小编带来了王者荣耀角色迁移iOS区转安卓区详情&#xff0c;一起来看看吧。 王者荣耀角色迁移iOS区转安卓区详情 …

ios系统换成android系统 游戏,2020王者荣耀苹果转换安卓系统 王者苹果转换安卓系统怎么转...

2020王者苹果怎么转换安卓系统?王者苹果转换安卓系统怎么转?相信很多IOS玩家都想换成安卓手机&#xff0c;可是却不知道怎么把游戏账号转移到安卓系统上。关于相关的转移操作&#xff0c;就随琵琶网小编来了解一下吧! 2020王者苹果怎么转换安卓系统? 很多IOS都有看到自己身边…

个性闹钟屏保带滚动字幕

基于我的时间工具&#xff08;有数字版和插件版&#xff09;的衍生修改而来 功能&#xff1a; 1&#xff09;滚动字幕可滚动可静止&#xff0c;可自定义文本 颜色 速度等&#xff0c;类似LED电子显示屏 &#xff08;或投影仪投屏使用&#xff09; 2&#xff09;带阴历 阳历 …

自定义屏保

先创建一个form窗体应用&#xff0c;然后在里面放几个文本框&#xff0c; 然后双击这个窗体进入代码页面 开始初始化的代码 隐藏或者显示Label控件&#xff0c;以及要改变的对象 在显示或者预览和屏保前&#xff0c;对所有的控件进行控制 屏保的设置。计算器、背景等

Win10屏保设置位置在哪里可以找到

如果我们感觉自己在离开电脑时&#xff0c;屏幕容易耗电&#xff0c;或者不想被看到屏幕内容&#xff0c;就可以设置屏幕保护&#xff0c;那么win10屏保设置在哪里呢&#xff0c;其实个性化中就能设置。 更多重装系统教程尽在小白系统重装官网 1、首先右键桌面空白处&#xf…

win7计算机锁频图片怎么设置,win7电脑锁屏壁纸怎么设置为个性化图片?

当我们每天使用win7系统电脑时&#xff0c;如果我们暂时离开电脑&#xff0c;系统会自动进入锁屏状态&#xff0c;但是有些用户认为默认的锁屏壁纸太单调&#xff0c;一点都不美观。很多用户想修改锁屏界面壁纸&#xff0c;那么win7电脑锁屏壁纸怎么设置呢&#xff1f;以下小编…

c++11 标准模板(STL)(std::basic_fstream)(五)

定义于头文件 <fstream> template< class CharT, class Traits std::char_traits<CharT> > class basic_fstream : public std::basic_iostream<CharT, Traits> 类模板 basic_fstream 实现基于文件的流上的高层输入/输出。它将 std::basic_i…

Vue在页面输出JSON对象,测试接口可复制使用

效果图&#xff1a; 数据处理前&#xff1a; 数据处理后&#xff1a; 代码实现&#xff1a; HTML: <el-table height"600" :data"tableData" border style"width: 100%" tooltip-effect"dark" size"mini"><el-…

接触式静电压测试仪的使用场景和注意事项

接触式静电压测试仪是一种用于测量物体表面静电电势的工具。它使用金属接触针或传感器接触待测试物体表面&#xff0c;通过测量传感器和地面之间的电势差来确定物体表面的静电电势。 接触式静电压测试仪通常用于以下场景&#xff1a; 1. 静电防护&#xff1a;在静电敏感环境中…

3dsmax中计算机快捷键大全,3Dmax快捷键大全

A——角度捕捉开关 B——切换到底视图 C——切换到摄像机视图 D——封闭视窗 E——切换到轨迹视图 F——切换到前视图 G——切换到网格视图 H——显示通过名称选择对话框 I——交互式平移 J——选择框显示切换 K——切换到背视图 L——切换到左视图 M——材质编辑对话框 N——动…

手机测试要点大全

功能测试&#xff08;Functional Testing&#xff09;是最基本的测试&#xff0c;主要 根据需求规格说明书验证功能是否实 功能测试要点&#xff1a; 1.多考虑用户是在什么情况下如何使用该功能。 如&#xff1a;断网的时候访问网站&#xff0c;或者使用键盘快捷键进行操作等…

IMU惯性测量单元相关技术(概念版)

重要说明&#xff1a;本文从网上资料整理而来&#xff0c;仅记录博主学习相关知识点的过程&#xff0c;侵删。 一、参考资料 新手入门系列3——Allan方差分析方法的直观理解 惯性测量单元Allan方差分析详解 IMU误差&测量模型 IMU标定之—Allan方差 IMU误差模型简介及VINS…

RPG Maker MV之起始队伍设置

新建一个游戏工程&#xff0c;默认运行&#xff0c;你可以开心的控制一个人物在初始地图行走&#xff0c;但是&#xff0c;人物后面跟着3个其他人物&#xff0c;我们一般游戏刚开始玩家只有1人&#xff0c;之后随着剧情的发展&#xff0c;慢慢加入新的游戏人物到玩家队伍里&…

RPG Maker MV 旅馆和商店

目录 旅馆 商店 旅馆 绘制出一个旅馆的样子&#xff0c;然后快速设置旅店即可。 下图是旅店的自动生成代码&#xff0c; 商店 绘制好商店&#xff0c;图中这个是商人。 注意下图的价格是你购买物品时选择标准时的价格&#xff0c;也是你出售物品的价格一半&#xff0c;

RPG

J2ME RPG游戏边学边做&#xff08;一&#xff09;   笔者以前是做j2ee的&#xff0c;一个月前由于兴趣所致开始利用业余时间学习j2me游戏开发。在网上看了一通教程后&#xff0c;便准备动手一边学一边做一个简单的rpg游戏。虽然起点比较高&#xff0c;但感觉游戏难度越大&…

RPG Maker MV-场所移动

绘制两张地图 第一张地图是世界&#xff0c;第二张是外观。 在事件模式中快速创建场所移动&#xff0c;从第一张图移动到第二张。 剩余的懒得再从语雀搬过来了。 我的语雀笔记

RPGMaker MV 插件基础02:插件的参数定义

回顾上一节&#xff0c;我们创建了一个test.js文件&#xff0c;对应的插件名称就是test&#xff0c;我们定义了插件的名称&#xff0c;作者与帮助信息&#xff0c;这节讲一下如何定义插件的参数并且通过js代码获得参数 还是接着上一节的js文件&#xff0c;在定义作者与帮助信息…