网络编程 -day5-poll select复习-getsockopt()-广播

1、结合并发TCP的IO多路复用poll监测表复习

//server.c
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(){
//socket - IPv4 - TCP
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(-1 == sockfd)
    {
        perror("socket");
        return -1;
    }
    printf("创建成功sockfd = %d\n",sockfd);

//bind - struct - 三个参数-sockfd,(struct sockaddr *)&saddr,sizeof(saddr)
    struct sockaddr_in saddr;    
    saddr.sin_family = AF_INET;
    saddr.sin_port   = htons(8848);
    saddr.sin_addr.s_addr = inet_addr("192.168.7.26");
    if(-1 ==  bind(sockfd,(struct sockaddr *)&saddr,sizeof(saddr)))
    {
        perror("bind");
        return -1;
    }
    printf("绑定成功\n");

//listen - 两个参数 - sockfd - int n
    if(-1 == listen(sockfd,10))
    {
        perror("listen");
        return -1;
    }
    printf("监听成功\n");

//poll - 定义结构体- 初始化为负数 - 添加文件描述符sokcfd 
    struct polled fds[32];
    for (int i=0;i<32;i++)
    {
        fds[i].fd = -1;
    }
    int nfds = 0;                //实际文件描述符个数
    fds[nfds].fd = sockfd;
    fds[nfds].events = POLLIN;    //POLLIN读 POLLOUT写 读写相同表示产生IO事件
    nfds ++;
    while(1)
    {
        poll(fd,nfds,-1)
        //int poll(struct pollfd *fds, nfds_t nfds, int timeout); timeout=-1表示阻塞等待事件
        for (int i=0;i

2、 设置/获取套接字属性函数 -- getsockopt() -- setsockopt()

       头文件:#include     #include

函数原型:int getsockopt  (int sockfd, int level, int optname,void *optval, socklen_t *optlen);

                  int setsockopt  (int sockfd, int level, int optname,const void *optval, socklen_t optlen);

          参数:


    sockfd:套接字
    level:设置属性层
            SOL_SOCKET:通用套接字层
            IPPROTO_IP:IP层
            IPPRO_TCP:TCP层

网络编程 -day5-poll select复习-getsockopt()-广播_第1张图片

举例1:设置端口复用

sockfd = socket(AF_INET,SOCK_STREAM,0);

int opt = 1;
setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));

举例2:设置广播属性

//UDP IPv4 发送端(客户端)
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);

int opt = 1;
setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,&opt,sizeof(opt));

//绑定接收方端口和广播地址
//发送数据

举例3:将指定IP加入到组播中

//UDP IPv4 接收方(服务端)
int sockfd = socket(AF_INET,SOCK_DGRAM,0);
//加入多播组
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr("224.10.10.10");
mreq.imr_interface.s_addr = inet_addr("0.0.0.0");
setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));
//sockfd - ip 绑定
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port   = htons(8848);
saddr.sin_addr.s_addr = inet_addr("0.0.0.0");
bind(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));
//等待接收数据
char buf[32] = {0};
while(1){
       recvfrom(sockfd,buf,sizeof(buf),0,NULL,NULL);
       printf("buf:%s\n",buf);
       memset(buf,0,sizeof(buf));
}

3、 网络超时监测的三种用法 -- setsockopt()  -- alarm() -- IO多路复用

setsockopt()

struct timeval timeout = {5,0}    //grep -r -n "struct timeval {" /usr/include/  可查结构体
//接收超时
setsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,&timeout,sizeof(timeout));    //注意第四个四五个参数

alarm()

void hanlder(int arg){
    printf("timeout!\n");
}
int main(){
    signal(SIGALRM,handler);
    alarm(5);    
//程序运行开始后,开始循环打印hello,后台计时,5秒到了之后,发送SIGALRM信号(定时终止程序)
//加了handler参数后,将会执行handler函数来取代发送定时终止信号
//如果此处加pause() 刚开始将会一次都不打印hello,后台计时5s后直接执行hanlder函数
//等同于raise(SIGALRM)    
//signal宏函数复习:SIG_DFL  SIG_IGN
     while(1){
        printf("hello\n");
        sleep(1);
    }
    return 0;  
}

IO多路复用--select--poll

select poll epoll函数参数中将最后一个参数NULL改为&timeout(struct timeval类型)

//select
struct timeval timeout = {5,0}; //5s + 0us
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(sockfd,&rfds);
int maxfd = sockfd;
select(maxfd+1,&rfds,NULL,NULL,&timeout); //多配置一个超时等待时间
//
 poll(fds,nfds,-1);//阻塞等待事件
//NULL -- 阻塞等待

4、广播

网络号(网段)、主机号

网段:192.168.7 由ip地址和子网掩码255.255.255.0相与得来

xxx.xxx.xxx.255是广播地址

广播与UDP:UDP不关注对方是否收到

举例1:send.c -- 正常UDP多个设置属性(socket-setsockopt-struct-sendto)

//send.c
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
int main(){
//socket
int sockfd = socket(AF_INET,SOCK_DGRAM,0);
if (sockfd<0){
    perror("socket");
    return -1;
}
//setsockopt
int opt = 1;
setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,&opt,sizeof(opt));
//设置接收方端口信息
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port   = htons(8848);
    saddr.sin_addr.s_addr = inet_addr("192.168.7.255");    //ip填广播地址
//read sendto
char buf[32] = {0};
while(1){
    read(0,buf,sizeof(buf));
    sendto(sockfd,buf,sizeof(buf),(struct sockaddr *)&saddr,sizeof(saddr));
    memset(buf,0,sizeof(buf));
}
return 0;
}

举例1:recv.c -- UDP(socket-struct-bind-recvfrom)

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
int main(){
//socket    数据报套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM,0);    
    if (sockfd<0){
        perror(""socket);
        return -1;
    }
//bind
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port   = htons(8848);    //收听同一个广播,端口和地址都必须相同
    saddr.sin_addr.s_addr = inet_addr("192.168.7.255");    //也可以填0.0.0.0
    bind(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));
//recvfrom
    char recvBuf[32] = {0};
    while(1)
    {       
        recvfrom(sockfd,recvBuf,sizeof(recvBuf),0,NULL,NULL);
        printf("recvBuf:%s\n",recvBuf);
        memset(recvBuf,0,sizeof(recvBuf));
    }
return 0;
}

广播 -- 小结

//广播 -- 总结
发送方:
1.socket
2.setsockopt(sockfd,SO_SOCKET,SOBROADCAST,&opt,sizeof(opt));
3.指定发送方端口信息(端口+广播地址 结构体)
4.while(1){sendto(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&sockaddr,sizeof(saddr))}
接收方(服务器):
1.socket
2.bind绑定接收方端口信息(端口+广播地址 结构体)
3.while(1){recvfrom(sockfd,buf,sizeof(buf),NULL,NULL}
      
UDP才能广播                  
发送方向广播地址发送数据,所有绑定了广播地址和同样端口的接收方都能收到  

网络地址

网络编程 -day5-poll select复习-getsockopt()-广播_第2张图片

5、组播

举例1:send.c -- UDP(socket-struct-sendto) 注意地址

//send.c
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
int main(){
//socket
int sockfd = socket(AF_INET,SOCK_DGRAM,0);
//指定接收方 -- 组播地址
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port   = htons(8848);
saddr.sin_addr.s_addr = inet_addr("224.10.10.10");
//sendto
    char sendBuf[32] = {0};
    while(1)
    {
        read(0,sendBuf,sizeof(sendBuf));
        sendto(sockfd,sendBuf,sizeof(sendBuf),0,(struct sockaddr *)&saddr,sizeof(saddr));
    }

    return 0;

}

举例1:recv.c -- UDP多个加入多播组(socket-setsockopt-struct-bind-recvfrom) 注意地址

   //recv.c
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char *argv[])
{ 
//socket
    int sockfd = socket(AF_INET,SOCK_DGRAM,0);
//加入多播组
    struct ip_mreq mreq;
    mreq.imr_multiaddr.s_addr = inet_addr("224.10.10.10");
    mreq.imr_interface.s_addr = inet_addr("0.0.0.0");
    setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));
//bind
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port   = htons(8848);
    saddr.sin_addr.s_addr = inet_addr("0.0.0.0");
    bind(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));
//recvfrom
    char recvBuf[32] = {0};
    while(1)
    {
        recvfrom(sockfd,recvBuf,sizeof(recvBuf),0,NULL,NULL);
        printf("recvBuf:%s\n",recvBuf);
        memset(recvBuf,0,sizeof(recvBuf));
    }
    return 0;
}

6、Unix  --    无需地址(struct sockaddr_un saddr = {AF_UNIX, "socket"})

举例1:server.c -- UDP(socket-struct-bind-recvfrom)

AF_UNIX 而非IPv4的AF_INET

    //AF_INET;--->ipv4 --->struct sockaddr_in 
    //AF_UNIX;--->struct sockaddr_un
    //struct sockaddr_un saddr ={AF_UNIX,"socket"};

//UDP -- AF_UNIX
//server.c
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
int main(int argc, char *argv[])
{ 
//socket
    int sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);
//bind
    struct sockaddr_un saddr;
    saddr.sun_family = AF_UNIX;
    strcpy(saddr.sun_path,"socket");
    bind(sockfd,(struct sockaddr *)&saddr, sizeof(saddr));//转为通用结构体
//recvfrom
    char recvBuf[32] = {0};
    while(1){
        recvfrom(sockfd,recvBuf,sizeof(recvBuf),0,NULL,NULL);
        printf("recvBuf:%s\n",recvBuf);
        bzero(recvBuf,sizeof(recvBuf)) //memset
}
    return 0;
} 

举例1:client.c -- UDP (socket-struct-sendto)注意AF_UNIX和struct

//client.c
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char *argv[])
{ 
    //socket
int sockfd = socket(AF_UNIX,SOCK_DGRAM,0);
    //struct
struct sockaddr_un saddr = {AF_UNIX,"socket"};
//    saddr.sun_family = AF_UNIX;
//    strcpy(saddr.sun_path,"socket");

    //sendto
    char sendBuf[32] = {0};
while(1){
        read(0,sendBuf,sizeof(sendBuf));
        sendto(sockfd,sendBuf,sizeof(sendBuf),0,(struct sockaddr *)&saddr,sizeof(saddr));
        //别忘了中间有个flags -- 0
        bzero(sendBuf,sizeof(sendBuf));
}
return 0;
}

7、需要注意的细节

poll:
流程:strct polled fds[32]-> for -1-> nfds=0->添加fds[nfds].fd=sockfd;fds[nfds].events=POLLIN->while(1){poll(fds,nfds,-1)}
//poll的三个参数:结构体首地址、元素个数、超时(-1表示阻塞等待事件)

select:
流程:fd_set rfds,tmp;FD_ZERO;FD_SET;maxfd; while(1){select(nfds=maxfd+1,&tmp,NULL,NULL,&timeout)}
//注意第一个参数是表的元素个数,而maxfd是最大的文件描述符

setsockopt()设置套接字属性参数
//参数:(sockfd,SOL_SOCKET,SO_BROADCAST,&timeout,sizeof(timeout)

alarm(5)
//表示程序运行开始后,后台计时5s然后发送程序终止信号(SIGALRM)
//signal(5,hanlder)函数中,表示执行hanlder取代原先的信号发送

广播-UDP-IPv4
send:socket-setsockopt-struct-sendto
recv:socket-struct-bind-recvfrom

组播-UDP-IPv4
send:socket-struct-sendto
recv:socket-setsockopt-struct-bind-recvfrom

Unix-UDP-AF_UNIX
server:socket-struct-bind-recvfrom
client:socket-struct-sendto

你可能感兴趣的:(c#,网络协议)