网络------利用socket编程实现简单的UDP网络程序

之前已经介绍过socket编程了,并且实现了一个简单TCP网络程序
https://blog.csdn.net/qq_34021920/article/details/80153071
现在再来实现一个简单的UDP程序,来看看需要用到的操作


注:UDP同样需要利用socket函数创建套接字,然后利用bind函数进行绑定。在这里就不再做详细介绍(链接戳上面),在这里介绍一下UDP进行数据读写的操作

1.发送数据

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

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
             const struct sockaddr *dest_addr, socklen_t addrlen);

sockfd:是要发送的socket描述符
buf:待发送数据的缓冲区
len:缓冲区长度
flags:调用方式标志位,一般为0, 改变flags,将会改变sendto发送的形式
dest_addr:指向目的套接字的地址
addrlen:所指地址的长度

返回值:成功返回实际传送出去的字符数,失败返回-1。

2.接受数据

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


ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                 struct sockaddr *src_addr, socklen_t *addrlen);

sockfd:标识一个已连接的socket描述符
buf:接受缓冲区
len:接受缓冲区长度
flags:调用操作方式,一般设置为0
src_addr:指向装有源地址的缓冲区
addrlen:缓冲区长度

返回值:成功返回接收到的字符数,失败返回-1。


在之前实现TCP的代码中,我们用到了一些地址转换函数,UDP中同样需要。在这里介绍一下
sockaddr_in中的成员struct in_addr sin_addr表示32位的IP地址,但是我们通常用点分十进制的字符串表示IP地址,所以就需要将字符串转换为in_addr类型,以下函数可就可以实现这个功能:

点分十进制字符串转为32位的网络字节序

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int inet_aton(const char *cp, struct in_addr *inp);

in_addr_t inet_addr(const char *cp);

int inet_pton(int af, const char *src, void *dst);

上面的三个函数都是将点分十进制字符串转换成整数
1. inet_aton
返回值:若字符串有效则返回1,否则返回0
参数cp:输入型参数,要转换的IP地址
参数inp:输出型参数,保存转换后的内容

2.inet_addr
返回值:若字符串有效则返回32位二进制网络字节序的IPv4地址,否则返回INADDR_NONE
参数cp:要转换的IP地址

3.inet_pton
返回值:若成功则返回1,若输入不是有效的表达格式则返回0,若出错则返回-1
参数af:地址族,我们使用的IPV4则为AF_INET
参数src:指向要转换IP地址字符串的地址
参数dst:保存转换后的内容

< 注:inet_addr函数存在一些问题,所有2^32个可能的二进制值都是有效的ip地址(0.0.0.0-255.255.255.255),但是当出错时函数返回INADDR_NONE常量(通常是一个32位均为1的值),这意味着点分十进制数串255.255.255.255不能由该函数处理,因为它的二进制用来指示该函数失败 >

扫描二维码关注公众号,回复: 1052194 查看本文章

32位的网络字节序转为点分十进制字符串

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

char *inet_ntoa(struct in_addr in);

const char *inet_ntop(int af, const void *src,
                      char *dst, socklen_t size);

1.inet_ntoa
返回值:成功返回指向一个点分十进制字符串的指针,失败返回NULL
参数in:保存要转换的一个网络字节序

2.inet_ntop
返回值:成功返回一个指向指向点分十进制字符串的指针,失败返回NULL
参数af:地址族,我们使用的IPV4则为AF_INET
参数src:要转换的网络字节序
参数dst:不可以为空,必须为目标存储单元分配内存并制定其大小,调用成功时,这个指针就是返回值
参数size:指向缓存区dst的大小,避免溢出


实现简单的UDP网络程序

udp_server.c UDP服务器端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>


int main(int argc,char* argv[])
{
    if(argc!=3)
    {
        printf("Usage:%s ip port\n",argv[0]);
        return 1;
    }
    //创建套接字
    int sock=socket(AF_INET,SOCK_DGRAM,0);
    if(sock<0)
    {
        perror("socket");
        return -1;
    }
    printf("create socket ok\n");
    //初始化bind的参数
    struct sockaddr_in local;
    local.sin_family=AF_INET;
    local.sin_port=htons(atoi(argv[2]));
    local.sin_addr.s_addr=inet_addr(argv[1]);
    //绑定
    int b=bind(sock,(struct sockaddr*)&local,sizeof(local));
    if(b<0)
    {
        perror("bind");
        return -2;
    }
    printf("bind ok\n");

    //发送接收消息
    char buf[521];
    while(1)
    {
        socklen_t len=sizeof(local);
        ssize_t s=recvfrom(sock,buf,sizeof(buf)-1,0,(struct sockaddr*)&local,&(len));
        if(s>0)
        {
            buf[s]=0;
            if(strcmp(buf,"quit")==0)
            {
                printf("client quit!\n");
                break;
            }
            printf("[%s:%d]:%s\n",inet_ntoa(local.sin_addr),ntohs(local.sin_port),buf);
            sendto(sock,buf,strlen(buf),0,(struct sockaddr*)&local,len);
        }
    }

    return 0;
}

udp_client.c UDP客户端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>


int main(int argc,char* argv[])
{
    if(argc!=3)
    {
        printf("Usage:%s ip port",argv[0]);
        return 1;
    }
    //创建套接字
    int sock=socket(AF_INET,SOCK_DGRAM,0);
    if(sock<0)
    {
        perror("socket");
        return -1;
    }
    struct sockaddr_in local;
    local.sin_family=AF_INET;
    local.sin_port=htons(atoi(argv[2]));
    local.sin_addr.s_addr=inet_addr(argv[1]);

    //发送接收消息
    char buf[521];
    struct sockaddr_in peer;
    while(1)
    {
        printf("Please Enter:");
        fflush(stdout);
        socklen_t len=sizeof(peer);
        ssize_t s=read(0,buf,sizeof(buf)-1);
        if(s>0)
        {
            buf[s-1]=0;
            sendto(sock,buf,strlen(buf),0,(struct sockaddr*)&local,len);
            if(strcmp(buf,"quit")==0)
            {
                break;
            }
            ssize_t num=recvfrom(sock,buf,sizeof(buf)-1,0,(struct sockaddr*)&local,&(len));
            if(num>0)
            {
                buf[s]=0;
                printf("server say:%s\n",buf);
            }
        }
    }
    return 0;
}

运行结果:
在这里同样利用本地IP127.0.0.1来进行测试
这里写图片描述
这里写图片描述

猜你喜欢

转载自blog.csdn.net/qq_34021920/article/details/80160353
今日推荐