概述
前面概念中简单提到,UDP是无连接的不可靠的数据报协议,非常不同于TCP面向连接的可靠字节流。然而,相比TCP有些场合更适合使用UDP,例如常见的应用程序有:DNS(域名系统)、NFS(网络文件系统)和SNMP(简单网络文件管理系统)等。
根据应用场景,给出不同的UDP服务端代码、客户端代码:
(1)服务端、客户端都接受、发送一次数据
(2)服务端可不断接收客户端的,并能区分多客户端
(3)服务端echo服务,客户端发送并回显
本文讲解第三篇。
1、UDP echo服务
在上一节的基础上,服务端接收来自个客户端的消息,并将接收到的消息发给客户端。客户端仅处理一次对客户端发送、接收消息。
1.1 流程图
echo的服务流程如下:
先启动服务端,服务端创建socket、绑定地址之后,调用recvfrom阻塞等待客户端数据到来。客户端创建socket,直接使用sendto向服务端发送数据,客户端调用recvfrom阻塞等待接收数据。服务端收到数据,打印输出,调用sendto将接收的数据发送到客户端,再次进入等待接收数据循环。客户端收到服务端的回复数据,打印输出,关闭退出。
1.2 服务端代码
在上一博文"网络编程(6)UDP套接字编程(2)UDP服务端
"基础上,服务端recvfrom之后增加sendto代码。
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h> // sockaddr_in, inet_addr
#include <unistd.h> // close
#include <cstring>
#include <errno.h>
const char *SRV_ADDR = "127.0.0.1";
int SRV_PORT = 8080;
int main()
{
/// 1、创建socket
int socket_fd = ::socket(AF_INET, SOCK_DGRAM, 0); // udp
if (socket_fd == -1){
printf("%s: create socket failed. %sn", __func__, strerror(errno));
return 1;
}
else{
printf("%s: create socket (fd = %d) success.n", __func__, socket_fd);
}
/// 2、绑定到本地端口
sockaddr_in servaddr;
servaddr.sin_family = AF_INET; // IPv4
//servaddr.sin_addr.s_addr = inet_addr(SRV_ADDR); //仅支持IPv4
inet_pton(servaddr.sin_family, SRV_ADDR, &servaddr.sin_addr); // 新函数,通用IPv4/6
servaddr.sin_port = htons(SRV_PORT);
int ret = ::bind(socket_fd, (const sockaddr *)&servaddr, sizeof(servaddr));
if (ret == -1){
printf("%s: bind %s:%d failed. %s n", __func__, SRV_ADDR, SRV_PORT,strerror(errno));
return 1;
}
else{
printf("%s: bind %s:%d success.n", __func__, SRV_ADDR, SRV_PORT);
}
/// 3、等待接收和响应
char buf[1024]; // 发送
sockaddr_in clientaddr;
socklen_t socklen = sizeof(clientaddr);
while (1)
{
// 接收客户端数据
int len = ::recvfrom(socket_fd, buf, sizeof(buf), 0, (struct sockaddr *)&clientaddr, &socklen);
if (len < 0){
printf("%s: recv failed. err %s n", __func__, strerror(errno));
break;
}
else{
// 获取客户端的ip、和port
char ip[INET6_ADDRSTRLEN];
inet_ntop(clientaddr.sin_family, &clientaddr.sin_addr, ip, socklen);
int port = ntohs(clientaddr.sin_port);
printf("%s: client [%s:%d] recv %2d: %sn", __func__, ip, port, len, buf);
}
// 接收到的数据发送给客户端
len = ::sendto(socket_fd, buf, sizeof(buf), 0, (struct sockaddr *)&clientaddr, socklen);
if (len < 0){
printf("%s: send failed. err %s n", __func__, strerror(errno));
break;
}
}
/// 4、关闭连接
::close(socket_fd);
}
1.3 客户端代码
客户端的代码略做修改,增加出错处理,已经在sendto后调用recvfrom接收服务端返回数据。
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h> // sockaddr_in, inet_addr
#include <unistd.h> // close
#include <cstring>
#include <errno.h>
const char *SRV_ADDR = "127.0.0.1";
int SRV_PORT = 8080;
int main()
{
/// 1、创建socket
int socket_fd = ::socket(AF_INET, SOCK_DGRAM, 0); // udp
if(socket_fd == -1){
printf("%s: create socket failed.n", __func__);
return -1;
}else{
printf("%s: create socket (fd = %d) success.n", __func__, socket_fd);
}
// 2、 发送到服务端
sockaddr_in servaddr;
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr(SRV_ADDR);
servaddr.sin_port = htons(SRV_PORT);
int len ;
char buf[1024] = "hello sockte!";
// 发送
len = ::sendto(socket_fd, buf, strlen(buf), 0, (sockaddr*)&servaddr, sizeof(servaddr));
if(len < 0){
printf("%s: send failed. %s n", __func__, strerror(errno));
return 1;
}
// 接收
//len = ::read(socket_fd, buf, strlen(buf));
//len = ::recv(socket_fd, buf, strlen(buf), 0);
len = ::recvfrom(socket_fd, buf, strlen(buf), 0,NULL, NULL); // 同上
if(len < 0){
printf("%s: recv failed. %s n", __func__, strerror(errno));
return 1;
}
else{
printf("recv %2d: %sn", len, buf);
}
// 3、关闭退出
::close(socket_fd);
1.4 测试
打开服务端后,多次打开客户端,可以看到服务端能够正常工作,结果如下
最后
以上就是微笑鸡翅为你收集整理的网络编程(6)UDP套接字编程(3)UDP echo服务1、UDP echo服务1.2 服务端代码的全部内容,希望文章能够帮你解决网络编程(6)UDP套接字编程(3)UDP echo服务1、UDP echo服务1.2 服务端代码所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复