Bootstrap

LinuxUDP编程

         由于UDP是无连接、尽力传输的,所以Server端绑定完IP、端口号后,使用recvfrom可以阻塞等待客户端的数据,而且Client端通过sendto发送的数据包直接发送到互联网(也是基于IP、端口号)这种操作是不担保Server端是否收到的,适用于实时音视频传输DNS的域名解析

一、Sendto

实际上,sendto和recvfrom都是对于send和recv的扩展-----增加参数(用于绑定IP、端口号)

因为UDP是无连接的,想要传输信息实际上还是需要对象的信息,只不过它的信息不用像TCP编程中实际地对sock_fd进行绑定,而是直接通过参数绑定

#include <sys/types.h>
#include <sys/socket.h>

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags
              struct sockaddr *dest_addr, socklen_t addrlen
              )
    
params: 前三个参数同write
    	flags		一般填0---此时同write
    				MSG_DONTWAIT 非阻塞版本
    				MSG_OOB 用于发送TCP类型的带外数据(out-of-band)
    	dest_addr	目标的结构体指针(配置IP、端口号)
    	addrlen		目标的结构体大小

二、Recvfrom

#include <sys/types.h>
#include <sys/socket.h>

ssize_t recvfrom(int sockfd, const void *buf, size_t len, int flags
              struct sockaddr *src_addr, socklen_t *addrlen
              )
    
params: 前三个参数同read
    	flags		一般填0---此时同read
    				MSG_DONTWAIT 非阻塞版本
    				MSG_OOB 用于发送TCP类型的带外数据(out-of-band)
    	src_addr	发送方的结构体指针(配置IP、端口号)
    	addrlen		发送方的结构体大小的指针----注意和sendto中的区别!!
    
return: 成功返回收到字节数,失败返回-1

三、服务器端

 #include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h> //exit
#include <string.h> //bzero
#include <strings.h> //strncasecmp 忽略大小写比较
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define SERV_PORT (5001)
#define SERV_IP   "127.0.0.1"
#define BUFSIZE   (128)
#define QUIT_STR  "quit"

int main(void)
{
    int sock_fd;
    struct sockaddr_in sin,cin;

    //1.创建 注意套接字类型变化---数据报套接字
    sock_fd = socket(AF_INET,SOCK_DGRAM,0);
    if( sock_fd == -1)
    {
        perror("socket");
        exit(1);
    }
    //优化:允许绑定地址快速重用
    int b_reuse = 1;
	setsockopt (sock_fd, SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof (int));
    //2.绑定   
    bzero(&sin,sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port   = htons(SERV_PORT);
    sin.sin_addr.s_addr = htonl(INADDR_ANY);
    if( (bind(sock_fd,(struct sockaddr*)&sin,sizeof(sin))) < 0 )
    {
        perror("bind");
        exit(1);
    }
    //3.循环服务器模型
    char rd_buf[BUFSIZ];
    socklen_t cin_len = sizeof(cin);
    while(1)
    {
        bzero(rd_buf,BUFSIZ);
        if( recvfrom(sock_fd,rd_buf,BUFSIZ-1,(struct sockaddr*)&cin,&cin_len) < 0 )
        {
            perror("recvfrom");
            continue;
        } 
        //发送方的信息处理
        char cin_ip[16];
        if( inet_ntop(AF_INET,(void*)&cin.sin_addr,cin_ip,sizeof(cin)) == 0)
        {
            perror("inet_ntop");
            exit(1);
        }
        printf("Received from(%s:%d),data:%s",cin_ip,ntohs(cin.sin_port),rd_buf);

    }

    close(sock_fd);
    return 0;
}

四、客户端

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h> //exit
#include <string.h> //bzero
#include <strings.h> //strncasecmp 忽略大小写比较
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define SERV_PORT (5001)
#define SERV_IP   "127.0.0.1"
#define BUFSIZE   (128)
#define QUIT_STR  "quit"

void usage(char *s)
{
    printf("\nWarning:too few parameters!\n");
    printf("\n\t%s SERV_IP SERV_PORT\n",s);
    printf("SERV_PORT must > 5000\n");
}


int main(int argc, char **argv)
{
    if( argc != 3)
    {
        usage(argv[0]);
        exit(1);
    }

    int sock_fd;
    struct sockaddr_in sin;

    //1.创建
    sock_fd = socket(AF_INET,SOCK_DGRAM,0);
    if(sock_fd == -1)
    {
        perror("socket");
        exit(1);
    }
    //配置sockaddr_in信息---用于sendto
    bzero(&sin,sizeof(sin));
    sin.sin_family = AF_INET;
    //端口号、IP都从输入参数获得
    u_short port = (u_short)atoi(argv[2]);
    if(port<5000)
    {
        perror("port");
        exit(1);
    } 
    sin.sin_port = htons(port);
    if( inet_pton(AF_INET,argv[1],(void*)&sin.sin_addr) != 1)
    {
        perror("inet_pton");
        exit(1);
    }
    char wr_buf[BUFSIZE];
    while(1)
    {
        //键盘获取内容-->发送到服务器
        bzero(wr_buf,BUFSIZE);
        if( fgets(wr_buf,BUFSIZE-1,stdin) == NULL )
        {
            perror("fgets");
            continue;
        }
        sendto(sock_fd,wr_buf,strlen(wr_buf),0,(struct sockaddr*)&sin,sizeof(sin));
        if( strncasecmp(wr_buf,QUIT_STR,strlen(QUIT_STR)) == 0) //输入了quit
        {
            break;
        }

    }

    close(sock_fd);
    return 0;
}

;