• Linux 网络编程五(UDP协议)


    UDP和TCP的对比
    --UDP处理的细节比TCP少。
    --UDP不能保证消息被传送到目的地。
    --UDP不能保证数据包的传递顺序。
    --TCP处理UDP不处理的细节。
    --TCP是面向连接的协议
    --UDP是无连接协议
    --TCP保持一个连接
    --UDP只是把数据发送出去而已
    TCP的优点
    --TCP提供以认可的方式显示的创建连接和终止连接。
    --TCP保证可靠的,顺序的以及不会重复的数据传输。
    --TCP处理流控制。
    --TCP允许数据优先。
    --如果数据没有传送到,TCP套接字会返回出错提示。
    --TCP通过保持连接并将数据块分成更小的分片来处理大数据,而无需程序员编码处理。
    TCP的缺点
    --TCP需要创建并保持一个连接,给系统带来很大开销。
    --TCP数据传输效率低。
    并发机制
    1.增加server数量
    2.多层结构
    一台server同事支持1000个client
    中间件对于普通用户来讲是server,对于server是client,一个中间件同时支持1000个client
    中间件会遍历自己管理的1000个client,发现client需要连接server,才会将请求发送给server,不需要连接server的client就不向server发送请求
    多层结构的原理:利用不是client在同一时间内都需要向server发送请求,永远只有部分用户需要发送请求。
    UDP的优点
    --UDP不要求保持一个连接
    --UDP没有因接收方没有收到数据包重传而带来开销。
    --设计UDP目的是用于短应用和控制消息。
    --在一个数据包接一个数据包基础上,UDP要求的网络带宽比TCP小。
    UDP的缺点
    --程序员必须创建代码监测数据包的正确性,必要时重传。
    --程序员必须把大数据包分片。
    选择使用哪一种协议?
    --一些消息重要程度不高,或者有规律重复,可以使用UDP。
    --如果要传输一个重要的数据,丢失一点就会破坏整个数据,那么需要选择TCP。
    --telnet,ssh,http等基本都基于TCP。
    --流媒体为了保证很窄的网络带宽来传送更多的数据,基本采用UDP。
    多数游戏中,丢失来自某个用户的状态更新可能不会引起注意,所以采用UDP。
    设计用在局域网的应用可以采用UDP,因为在局域网中丢失数据包的可能性很低。
    使用UDP与TCP所用的代码基本类似,唯一的区别在于socket函数调用的时候的一个参数不同
    int socket(int domain,int type,int protocol);
    参数type为SOCK_STREAM代表TCP,SOCK_DGRAM代表UDP。
    对于TCP和UDP都可以使用recvfrom函数,但recv只能TCP使用。
    使用UDP发送数据。
    ssize_t sendto(int s,const void *buf,size_t len,int flags,const struct sockaddr *to,socklen_t tolen);
    参数s是指套接字描述符
    参数buf是发送数据buf内存地址指针
    参数len是发送数据的长度
    参数flags一般传0
    参数to是结构sockaddr的内存地址指针
    参数tolen是结构sockaddr的大小 UDP不需要握手机制,也不需要确认另一个系统是否有服务端在listen。
    成功返回发送的字节数,失败返回-1,并且设置errno
    使用UDP接收数据
    ssize_t recvfrom(int s,void * buf,size_t blen,int flags,struct sockaddr * from,socklen_t * fromlen);
    成功返回接收字节数,失败返回-1,并且设置errno;UDP不同于TCP/IP,就算发送端关闭,recvfrom也不会返回0,因为UDP是无连接协议。 UDP不需要listen,bind之后就可以接受数据了。 recv函数只是从UDP缓存中读数据(此时数据已经在自己的电脑上了),不是直接从网络中读数据,什么时候UDP缓存区满了,另一边的send函数才会停止发送数据。
    UDP发送广播消息
    IP地址由四个字节组成,每个字节十进制是0时,表示本机,十进制是255就是广播消息,
    例如:192.168.1.255这就是在 192.168.1.x这个局域网中广播消息
    但是255.255.255.255并无法在全世界广播消息,因为路由器会屏蔽局域网中广播消息,不会传递到公网上。
    代码如下
    int on = 1;
    if (setsockopt(st, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) == -1)
    {
      printf("setsockopt failed ! error message :%s
    ", strerror(errno));
      return -1;
    }
    sendto和recvform
    在UDP中,当UDP接收端,只要bind端口号,sendto发送的数据就会缓存到接收端的UDP缓存区中,如果缓存区已满,那么sendto函数便会报错(信息过长错误)。
    将域名转化为IP地址
    const char *getIPAddrbvHostname(const char *hostname)
    {
        static char s[128]={0};
        struct hostent *h;
        h=gethostbyname(hostname);
        strcpy(s,inet_ntoa(*((struct in_addr *)h->h_addr)));
        return s;
    }
    将struct sockaddr_in转化为IP地址
    const char *getIPAddrbvaddr(struct sockaddr_in *client_addr)
    {
        return inet_ntoa(client_addr->sin_addr);
    }
    void sockaddr_toa(const struct sockaddr_in *addr,char *IPAddr)
    {
        unsigned char *p=(unsiged char *)&(addr->sin_addr.s_addr);
        sprintf(IPAddr,"%u.%u.%u.%u",p[0],p[1],p[2],p[3]);
    }
    inet_ntoa()函数是一个线程不安全函数,这个函数返回的是字符串,
    而参数并没有传递字符指针(不是当前函数分配内存),这说明这个函数返回的字符串一定不在线程的栈上,不在本线程的栈上,就有可能被其他线程修改,导致错误。
    获取socket自身的sockaddr
    int getsockname(int sockfd,struct sockaddr *addr,socklen_t *addrlen);
    获取socket连接的远端sockaddr
    int getpeername(int sockfd,struct sockaddr *addr,socklen_t *addrlen);
  • 相关阅读:
    java.lang.ClassFormatError
    记一次油猴脚本开发笔记
    一次Linux服务器空间满的随笔解决记录
    配置文件报错:元素类型 "XXX" 必须后跟属性规范 ">" 或 "/>"
    利用字符编码集对中文长度的不同来判断字符串中有没有中文
    记一次Python爬虫开发经历
    MySQL java连接被拒绝:java.sql.SQLException: Access denied for user 'root'@'****' (using password: YES)
    【ArcObject】 AxTocControl:实现图层可移动
    PostgreSQL 主键自动增长
    【转】ArcObject与ArcEngine的联系与区别
  • 原文地址:https://www.cnblogs.com/zhanggaofeng/p/5878099.html
Copyright © 2020-2023  润新知