1. UDP简介

  UDP 和TCP 的区别包括 1. 面向字节流和面向报文 2. TCP必须要建立连接后才能进行数据交换,但是UDP则并没有连接的建立和释放过程。面向字节流说明,tcp报文段(segment)是没有边界的,当服务器发送多个报文段到客户端时,客户端可能会把着多个报文段合并成一个报文段进行接收。但是对于UDP来说,数据是通过报文段进行传输的。

  如果说TCP协议可以用打电话去比喻,那么UDP协议可以用邮箱来形容。用邮箱传递信息时,虽然有丢失的可能性。但是用户1发送的信件和用户2接受的信件肯定是相同的。

2. 用UDP编写echo server

  使用UDP,我们只需要修改一下socket函数的参数就OK了。

int client_sock = socket(PF_INET, SOCK_DGRAM, );

  然后就是创建两个表示客户端和服务端地址的sockaddr_in结构,其中serv_addr的各个字段需要我们自己填充。但是client_addr的各个字段是通过recvfrom通过指针进行自动填充。

struct sockaddr_in serv_addr, client_addr;

  填充serv_addr的各个字段:

 serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons();

   下来使用bind函数将套接字和服务器地址进行绑定。

 if (bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < ) {
err_exit("bind error");
}

  数据传输方面使用recv族和sendto进行数据传输,这里值得注意的是只有sendto中的sockaddr_in结构是需要手动填充的,sendto中的地址表示要发送的目标地址。recvfrom中的是获取数据的源地址。下图是echo服务器的交互流程。

      

3. 地址长度所遇到的一个坑

   在写echo服务器中遇到一个问题,服务器端在运行过程中总是会出现如下错误:
  在stackoverflow看了下知道了应该是sockaddr的问题。出问题的代码就是下面这一行。问题就在client_addr这块。
int sLen = sendto(serv_sock, buffer, rLen, MSG_CONFIRM,
(struct sockaddr *)&client_addr, recv_addr_len);

  client_addr是通过服务端调用recvfrom获取的,我心想这也不用我手动填啊,怎么就又错了。又反复看了书上的代码,确定地址的获取方式没有错,通过打印我发现地址确实有问题,端口和地址都不对。在网上搜了下 udp echo server的代码,用可以正常运行的代码和我的代码细细比对,终于发现了问题所在。问题就出在地址长度的初始化上,我一直以为recvfrom中的地址长度是值-返回模式,但是实际上这个值也是要在recvfrom中起作用的。如果这个值不正确,client_addr的值也是错误的,导致服务器无法正常的把数据发送到客户端。就酱。。。

socklen_t recv_addr_len = sizeof(client_addr); //正确的初始化方式
//socklen_t recv_addr_len; //错误的初始化方式
int rLen = recvfrom(serv_sock, buffer, MAX_LEN, MSG_WAITALL,
(struct sockaddr *)&client_addr, &recv_addr_len);

4. 参考

[3]  TCP/IP网络编程

 
 
 
 
 
 
 
 

网络编程-UDP echo server的更多相关文章

  1. Socket网络编程-UDP编程

    Socket网络编程-UDP编程 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.UDP编程概述 1>.UDP服务端编程流程 创建socket对象.socket.SOCK_ ...

  2. c/c++ 网络编程 UDP 设定MTU

    网络编程 UDP 设定MTU MTU(Maximun Transmisson Unit):一次送信的最大size. 在程序里动态改变MTU.注意:程序运行需要root权限. 程序运行的方法: sudo ...

  3. c/c++ 网络编程 UDP up/down 网卡

    网络编程 UDP up/down 网卡 在程序里动态改变网卡的状态.注意:程序运行需要root权限. 程序运行的方法: sudo ./a.out 1,关闭网卡 #include <stdio.h ...

  4. c/c++ 网络编程 UDP 改变网关和网卡名字

    网络编程 UDP 改变网关和网卡名字 在程序里动态改变网关和网卡名字 1,改变网卡名字 #include <stdio.h> #include <string.h> #incl ...

  5. c/c++ 网络编程 UDP 改变网卡的硬件地址

    网络编程 UDP 改变网卡的硬件地址 在程序里动态改变网卡的硬件地址 1,取得网卡的硬件地址 #include <stdio.h> #include <string.h> #i ...

  6. c/c++ 网络编程 UDP 改变IP地址

    网络编程 UDP 改变IP地址 在程序里动态改变主机的IP地址 1,改变ipv4的地址 #include <stdio.h> #include <string.h> #incl ...

  7. c/c++ 网络编程 UDP 用if_nameindex和ioctl取得主机网络信息

    网络编程 UDP 用if_nameindex和ioctl取得主机网络信息 getifaddrs函数取得的东西太多了,如果只想取得网卡名字和网卡编号可以用下面的2个函数. 1,if_nameindex ...

  8. c/c++ 网络编程 UDP 主机网络信息取得

    网络编程 UDP 主机网络信息取得 1,if_nametoindex 通过网卡名字取得网卡编号 2,if_indextoname 通过网卡编号取得网卡名字 #include <stdio.h&g ...

  9. c/c++ 网络编程 UDP 发送端 bind 作用

    网络编程 UDP 发送端 bind 作用 upd 发送端 调用bind函数的效果:把socket特定到一个指定的端口,如果不调用bind,内核会随机分配一个端口. upd 发送端 调用bind函数的目 ...

随机推荐

  1. 函数&回调函数&匿名函数&自调函数

  2. APOC官网触发器示例执行后Web页面一直转圈

    apoc使用触发器:如apoc官网指导 CREATE (d:Person {name:'Daniel'}) CREATE (l:Person {name:'Mary'}) CREATE (t:Pers ...

  3. 在Windows平台上运行Tomcat

    从之前的学习中知道,可以调用Bootstrap类将Toomcat作为一个独立的应用程序来运行,在Windows平台上,可以调用startup.bat批处理文件来启动Tomcat,或运行shutdown ...

  4. Pycharm有必要改的几个默认设置项以及快捷键

    最近在用Pycharm学习Python的时候,总有两个地方感觉不是很舒服,比如调用方法的时候区分大小写(thread就不会出现Thread,string就不会出现String)等,这让我稍稍有点不舒服 ...

  5. vs code 快捷键设置:选中字母可以快速全部转换为大写或小写

    文件--->首选项--->键盘快捷方式--->搜索:"大写"--->点击"转换为大写"左侧的加号,然后设置快捷键后按enter即可完成添 ...

  6. linux mysql-5.7.26 安装全记录

    买了个阿里云,自己折腾一下. 时间:2019年7月17日13:40:18 1.下载 wget https://cdn.mysql.com//Downloads/MySQL-5.7/mysql-5.7. ...

  7. 题解 UVA1316 【Supermarket】

    题目链接: https://www.luogu.org/problemnew/show/UVA1316 思路: 根据题目意思,我们需要用到贪心的思想,越晚过期的商品当然是越晚卖好.同时你假如有多个商品 ...

  8. O036、Snapshot Instance 操作详解

    参考https://www.cnblogs.com/CloudMan6/p/5510296.html   有时候系统损坏的很严重,通过 Rescue 操作无法修复,那么我们就得重新考虑通过备份恢复了. ...

  9. 11 Django实现WebSocket

    因为需要实时显示状态的需求,想到了websocket,但是Django原生不支持websocket,后来搜索到了chango-channels项目,可以实现次需求. 一.Channels 官方文档 二 ...

  10. node 基本搭建 server.js

    const express = require('express'); const expressStatic = require('express-static'); const bodyparse ...