网络编程-select

什么是UDP

  • UDP,是User Datagram Protocol的简称, 中文名是用户数据包协议,是 OSI 参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。UDP 协议基本上是IP协议与上层协议的接口。它是IETF RFC 768是UDP的正式规范。UDP协议的主要作用是将网络数据流量压缩成数据包的形式。一个典型的数据包就是一个二进制数据的传输单位。每一个数据包的前8个字节用来包含报头信息,剩余字节则用来包含具体的传输数据。

TCP与UDP的区别

TCP(传输控制协议):

  1. 提供IP环境下的数据可靠传输(一台计算机发出的字节流会无差错的发往网络上的其他计算机,而且计算机A接收数据包的时候,也会向计算机B回发数据包,这也会产生部分通信量),有效流控,全双工操作(数据在两个方向上能同时传递),多路复用服务,是面向连接,端到端的传输;
  1. 面向连接:正式通信前必须要与对方建立连接。事先为所发送的数据开辟出连接好的通道,然后再进行数据发送,像打电话。
  1. TCP支持的应用协议:Telnet(远程登录)、FTP(文件传输协议)、SMTP(简单邮件传输协议)。TCP用于传输数据量大,可靠性要求高的应用。

UDP(用户数据报协议,User Data Protocol)

  1. 面向非连接的(正式通信前不必与对方建立连接,不管对方状态就直接发送,像短信,QQ),不能提供可靠性、流控、差错恢复功能。UDP用于一次只传送少量数据,可靠性要求低、传输经济等应用。
  1. UDP支持的应用协议:NFS(网络文件系统)、SNMP(简单网络管理系统)、DNS(主域名称系统)、TFTP(通用文件传输协议)等。

总结:

  1. TCP:面向连接、传输可靠(保证数据正确性,保证数据顺序)、用于传输大量数据(流模式)、速度慢,建立连接需要开销较多(时间,系统资源)。
  1. UDP:面向非连接、传输不可靠、用于传输少量数据(数据包模式)、速度快。

select

什么是I/O操作

  • 不是对 外围设备直接进行操作,而是对设备与cpu连接的接口电路的操作。

select的函数原型

int select(int nfds, fd_set *readfds, fd_set *writefds,
                  fd_set *exceptfds, struct timeval *timeout);

  • nfds:一个整型的变量,它比所有文件描述符集合中的文件描述符的最大值加1.
  • readfds:这个文件描述符集合监视文件描述符集中的每个文件是否有数据可读,当select()函数返回的时候,readfds将清除其中不可读的文件描述符,只留下可读的文件描述符
  • writefds:这个文件描述符集合监视文件描述符集中的每个文件是否有数据可写,当select()函数返回的时候,readfds将清除其中不可写的文件描述符,只留下可写的文件描述符
  • exceptfds:文件描述符集合监视文件描述符集中的每个文件是否发生错误
  • 成功过返回需要进行文件操作的描述符的个数.
  1. FD_CLR:将文件描述符从fd_set集里清楚
  2. FD_ISSET:判断这个文件描述符是否在这个集里
  3. FD_SET:将文件描述符fd加入集合set中
  4. FD_ZERO:将一个文件描述符集合清零
  1. 程序的作用是:从标准设备读入数据并打印出来
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/select.h>
#include <unistd.h>
#include <string.h>
void setMaxFd(int *pMax,int fd)
{
    if(*pMax<fd)
    {
        *pMax=fd;
    }
}

int main(void)
{
    int iMaxFd=0;
    fd_set readSet;
    int ret=-1;
    #if 0
    FD_ZERO(&readSet);
    FD_SET(STDIN_FILENO,&readSet);
    setMaxFd(&iMaxFd,STDIN_FILENO);
    //判断文件描述符中是否包含了某个文件描述符,若包含了返回1,不包含返回0
    int ret=FD_ISSET(STDIN_FILENO,&readSet);
    printf("ret=%d\n",ret);
  //  ret=FD_ISSET(STDOUT_FILENO,&readSet);
  //  printf("ret=%d\n",ret);
 # endif
    char caBuf[32]={'\0'};
    while(1)
    {   //select函数将会阻塞,直到有指定的文件描述符集合中有相应文件描述符要进行I/O操作
        FD_ZERO(&readSet);
        FD_SET(STDIN_FILENO,&readSet);
        setMaxFd(&iMaxFd,STDIN_FILENO);
        ret=select(iMaxFd+1,&readSet,NULL,NULL,NULL);
        if(ret==-1)
        {
            perror("select");
            return -1;
        }
        //若函数成功返回,文件描述符集合中只会包含将要进行I/O操作的文件描述符,其他没有要进行I/O操作的文件描述符会被清除掉
        //如果需要再监控,需要重新将清除掉的文件描述符添加到集合中
        //推荐做法,将集合清空
        //完成将所有需要监控的文件描述符都添加一遍
        if(FD_ISSET(STDIN_FILENO,&readSet))
        {
            memset(caBuf,'\0',sizeof(caBuf));
            read(STDIN_FILENO,caBuf,sizeof(caBuf));
            printf("%s\n",caBuf);
        }
    }
    printf("Hello World\n");
    return 0;
}

Paste_Image.png
  1. 从标准设备循环输入数据并且在标准设备循环输出数据
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/select.h>
#include <unistd.h>
#include <string.h>
void setMaxFd(int *pMax,int fd)
{
    if(*pMax<fd)
    {
        *pMax=fd;
    }
}

int main(void)
{
    int iMaxFd=0;
    fd_set readSet;
    fd_set writeSet;
    int ret=-1;
    int fd=-1;
#if 0
    FD_ZERO(&readSet);
    FD_SET(STDIN_FILENO,&readSet);
    setMaxFd(&iMaxFd,STDIN_FILENO);
    //判断文件描述符中是否包含了某个文件描述符,若包含了返回1,不包含返回0
    int ret=FD_ISSET(STDIN_FILENO,&readSet);
    printf("ret=%d\n",ret);
  //  ret=FD_ISSET(STDOUT_FILENO,&readSet);
  //  printf("ret=%d\n",ret);
 # endif
    int sockfd=-1;
    char caBuf[32]={'\0'};
    while(1)
    {   //select函数将会阻塞,直到有指定的文件描述符集合中有相应文件描述符要进行I/O操作
        FD_ZERO(&readSet);
        FD_ZERO(&writeSet);
        
        FD_SET(STDIN_FILENO,&readSet);
        setMaxFd(&iMaxFd,STDIN_FILENO);

        FD_SET(STDOUT_FILENO,&writeSet);
        setMaxFd(&iMaxFd,fd);

        ret=select(iMaxFd+1,&readSet,&writeSet,NULL,NULL);
        if(ret==-1)
        {
            perror("select");
            return -1;
        }
        //若函数成功返回,文件描述符集合中只会包含将要进行I/O操作的文件描述符,其他没有要进行I/O操作的文件描述符会被清除掉
        //如果需要再监控,需要重新将清除掉的文件描述符添加到集合中
        //推荐做法,将集合清空
        //完成将所有需要监控的文件描述符都添加一遍
        if(FD_ISSET(STDIN_FILENO,&readSet))
        {
            memset(caBuf,'\0',sizeof(caBuf));
            read(STDIN_FILENO,caBuf,sizeof(caBuf));
            printf("%s\n",caBuf);
        }
    }
    printf("Hello World\n");
    return 0;
}

Paste_Image.png
  1. 就从标准设备输入一次,并且输出
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/select.h>
#include <unistd.h>
#include <string.h>
void setMaxFd(int *pMax,int fd)
{
    if(*pMax<fd)
    {
        *pMax=fd;
    }
}

int main(void)
{
    int iMaxFd=0;
    fd_set readSet;
    fd_set writeSet;
    int ret=-1;
    int fd=-1;
#if 0
    FD_ZERO(&readSet);
    FD_SET(STDIN_FILENO,&readSet);
    setMaxFd(&iMaxFd,STDIN_FILENO);
    //判断文件描述符中是否包含了某个文件描述符,若包含了返回1,不包含返回0
    int ret=FD_ISSET(STDIN_FILENO,&readSet);
    printf("ret=%d\n",ret);
  //  ret=FD_ISSET(STDOUT_FILENO,&readSet);
  //  printf("ret=%d\n",ret);
 # endif
    int sockfd=-1;
    char caBuf[32]={'\0'};
    //select函数将会阻塞,直到有指定的文件描述符集合中有相应文件描述符要进行I/O操作
        FD_ZERO(&readSet);
        FD_ZERO(&writeSet);
        
        FD_SET(STDIN_FILENO,&readSet);
        setMaxFd(&iMaxFd,STDIN_FILENO);

        FD_SET(STDOUT_FILENO,&writeSet);
        setMaxFd(&iMaxFd,fd);

        ret=select(iMaxFd+1,&readSet,&writeSet,NULL,NULL);
        if(ret==-1)
        {
            perror("select");
            return -1;
        }
        //若函数成功返回,文件描述符集合中只会包含将要进行I/O操作的文件描述符,其他没有要进行I/O操作的文件描述符会被清除掉
        //如果需要再监控,需要重新将清除掉的文件描述符添加到集合中
        //推荐做法,将集合清空
        //完成将所有需要监控的文件描述符都添加一遍
        if(FD_ISSET(STDIN_FILENO,&readSet))
        {
            memset(caBuf,'\0',sizeof(caBuf));
            read(STDIN_FILENO,caBuf,sizeof(caBuf));
            printf("%s\n",caBuf);
        }
    
    printf("Hello World\n");
    return 0;
}

Paste_Image.png

数据报套接字(流程见书P127页)

运用UDP实现客户端与服务器之间的通信(PDU)

  • server.c
/*socket()*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h> //struct sockaddr_in
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/wait.h>
//要连接的端口号
#define MYPORT 5000
//能够接收的最长数据
#define MAXBUFLEN 100
int main(void)
{
    int sockfd;
    //本机的地址信息
    struct sockaddr_in serverAddr;
    //连接者的地址信息
    struct sockaddr_in clientAddr;
    int iLen;
    int numbytes;
    char caBuf[MAXBUFLEN];
    //取得一个文件描述符
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0))==-1)
    {
        //如果取得套接字描述符失败,则给出错误信息,退出
        perror("socket");
        exit(1);
    }
    //主机字节顺序
    serverAddr.sin_family = AF_INET;   //ipv4
    //网络字节顺序,短整型
    serverAddr.sin_port = htons(MYPORT); //port
    //server ip
    //自动设置为自己的IP
    serverAddr.sin_addr.s_addr = INADDR_ANY;
    //将结构的其余空间清零
    bzero(&(serverAddr.sin_zero), 8);
    //将sockfd和地址进行绑定    
    if(bind(sockfd, (struct sockaddr *)&serverAddr
                   , sizeof(serverAddr))==-1)
    {
        //如果绑定端口出错,则显示错误信息然后退出
        perror("bind");
        exit(1);
    }   
    iLen=sizeof(struct sockaddr);
    //接收数据
    if((numbytes=recvfrom(sockfd,caBuf,MAXBUFLEN,0,(struct sockaddr *)&clientAddr,&iLen))==-1)
    {
        //如果recvfrom()调用出错,则显示错误信息后退出
        perror("recvfrom");
        exit(1);
    }
    //显示接收到的数据
    printf("packet is %d bytes long\n",numbytes);
    caBuf[numbytes]='\0';
    printf("packet contains %s \n",caBuf);
    //关闭套接字连接
    close(sockfd);
}

Paste_Image.png
  • client.c

/*socket()*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h> //struct sockaddr_in
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/wait.h>
#define MYPORT 5000
int main(int argc,char *argv[])
{
    int sockfd;
    //连接者的地址信息
    struct sockaddr_in serverAddr;
    struct hostent *he;
    int numbytes;
    int ret=-1;
    if(argc!=3)
    {
        //检查是否有参数,如果没有则显示使用方法后退出
        fprintf(stderr,"usage:talker hostname message\n");
        exit(1);
    }
    if((he=gethostbyname(argv[1]))==NULL)
    {
        //取得主机的信息,如果失败则显示错误信息后退出
        herror("gethostbyname");    
        exit(1);
    }                                                                             
    if ((sockfd=socket(AF_INET, SOCK_DGRAM, 0))==-1)
    {
        //申请一个数据报套接字描述符,失败则退出
        perror("socket");
        exit(1);
    }
    //主机字节顺序
    serverAddr.sin_family = AF_INET;   //ipv4
    //网络字节顺序,短整型
    serverAddr.sin_port = htons(MYPORT); //port
    //server ip
    serverAddr.sin_addr= *((struct in_addr *)he->h_addr);
    //将结构中未用的部分清零
    bzero(&(serverAddr.sin_zero), 8);
    //发送数据  
    if((numbytes=sendto(sockfd,argv[2],strlen(argv[2]),0,(struct sockaddr *)&serverAddr,sizeof(struct sockaddr)))==-1)
    {
        //把信息发送到指定的主机指定端口,如出错则提示退出
        perror("recvfrom");
        exit(1);
    }
    //关闭套接字描述符后退出
    printf("send %d bytes\n",numbytes);
    close(sockfd);
    return 0;
}

Paste_Image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容

  • 简介 用简单的话来定义tcpdump,就是:dump the traffic on a network,根据使用者...
    保川阅读 5,940评论 1 13
  • 1. 网络编程概述 1.1 计算机网络 是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接...
    JackChen1024阅读 1,028评论 0 3
  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,849评论 6 13
  • 网络概念第一天 两台电脑怎么通过网络传输数据?怎样才能知道传输的是数据?谁摸过网线? 看电影,怎么看的?通过电流,...
    小吖朱阅读 1,537评论 0 1
  • iOS网络HTTP、TCP、UDP、Socket 知识总结OSI 七层模型我们一般使用的网络数据传输由下而上共有七...
    蜗牛也有梦想阅读 2,393评论 0 3