UDP通信发送和接收 || UDP实现全双工通信

recvfrom


    ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                        struct sockaddr *src_addr, socklen_t *addrlen);
    功能:
        从套接字中接收数据
    参数:
        sockfd:套接字文件描述符
        buf:存放数据空间首地址
        flags:属性 默认为0 
        src_addr:存放IP地址信息的空间首地址
        addrlen:存放接收到IP地址大小空间的首地址
    返回值:
        成功返回实际接收字节数
        失败返回-1 

修改虚拟机到桥接模式

    点击"虚拟机"
    点击"设置"
    点击"网络适配器"
    选择"桥接模式"
    点击"确定"

3.将网卡桥接到无线网卡
    点击"编辑"
    点击"虚拟网络编辑器"
    点击"更改设置"

4.在Ubuntu中重启网络服务
    sudo /etc/init.d/networking restart 

    ifconfig

bind 
    int bind(int sockfd, const struct sockaddr *addr,
                socklen_t addrlen);
    功能:
        在套接字上绑定一个IP地址和端口号
    参数:
        sockfd:套接字文件描述符
        addr:绑定IP地址空间首地址
        addrlen:绑定IP地址的长度
    返回值:
        成功返回0 
        失败返回-1 

UDP需要注意的细节点:

    1.UDP是无连接,发端退出,收端没有任何影响
    2.UDP发送数据上限,最好不要超过1500个字节
    3.UDP是不安全不可靠的,连续且快速的传输数据容易产生数据丢失

UDP包头长度:8个字节
    源端口号(2个字节)
    目的端口号(2个字节)
    长度(2个字节)
    校验和(2个字节)

wireshark

 抓包工具

  操作流程:
    1.sudo wireshark
      打开wireshark抓包工具
    2.选择抓取数据包的网卡
      any
    3.执行通信的代码
    4.停止通信
    5.设定过滤条件
        ip.addr == IP地址 
        udp 
        tcp 
        udp.port == 端口
 

使用UDP实现文件的发送

发送端代码:

/*************************************************************************
	> File Name: recv_file.c
	> Author: yas
	> Mail: rage_yas@hotmail.com
	> Created Time: Wed 06 Mar 2024 02:11:43 PM CST
 ************************************************************************/

#include<stdio.h>
#include "head.h"
int main(void)
{
    int sockfd = 0;
    struct sockaddr_in sendaddr;
    ssize_t nret = 0;
    char filename[1024] = {0};
    int pf = 0;
    char tmpbuff[1024] = {0};
    int nbyte = 0;

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1)
    {
        perror("fail to socket");
        return -1;
    }


    fgets(filename, sizeof(filename), stdin);

    sendaddr.sin_family = AF_INET;
    sendaddr.sin_port = htons(50000);
    sendaddr.sin_addr.s_addr = inet_addr("192.168.1.174");

    nbyte = sendto(sockfd, filename, strlen(filename), 0, (struct sockaddr *)&sendaddr, sizeof(sendaddr));
    if (nbyte == -1)
    {
        perror("fail to sendto");
        return -1;
    }
    
    pf = open(filename, O_RDONLY);
    if (pf == -1)
    {
        perror("fail to open");
        return -1;
    }

    while(1)
    {
        memset (tmpbuff, 0, sizeof(tmpbuff));
        nret = read(pf, tmpbuff, sizeof(tmpbuff));
        if(nret <= 0)
        {
            break;
        }
        nret = sendto(sockfd, tmpbuff, nret, 0, (struct sockaddr *)&sendaddr, sizeof(sendaddr));
    }

    close(pf);
    close(sockfd);

    return 0;
}

接收端代码:



#include<stdio.h>
#include "head.h"
int main(void)
{
    int sockfd = 0;
    ssize_t nsize = 0;
    struct sockaddr_in recvaddr;
    struct sockaddr_in sendaddr;
    ssize_t nret = 0;
    char filename[1024] = {0};
    socklen_t addlen = sizeof(recvaddr);
    int pf = 0;
    char tmpbuff[1024] = {0};
    int retbind = 0;

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1)
    {
        perror("fail to socket");
        return -1;
    }


    recvaddr.sin_family = AF_INET;
    recvaddr.sin_port = htons(50000);
    recvaddr.sin_addr.s_addr = inet_addr("192.168.1.174");

    retbind = bind(sockfd, (struct sockaddr *)&recvaddr, sizeof(recvaddr));
    if (retbind == -1)
    {
        perror("fail to bind");
        return -1;
    }

    //printf("!!!!!!!!!!!\n");
    nsize = recvfrom(sockfd, filename, sizeof(filename), 0,(struct sockaddr *)&sendaddr, &addlen);
    if (-1 == nsize)
    {
        perror("fail to recvfrom");
        return -1;
    }
    //printf("!!!!!!!!!!!\n");
    //printf("filename = %s\n", filename);

    pf = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664);
    if (pf == -1)
    {
        perror("fail to open");
        return -1;
    }

    while(1)
    {
        memset (tmpbuff, 0, sizeof(tmpbuff));
        nret = recvfrom(sockfd, tmpbuff, sizeof(tmpbuff), 0,(struct sockaddr *)&recvaddr, &addlen);
        if (nret <= 0)
        {
            break;
        }
        write(pf, tmpbuff, nret);
    }

    close(pf);
    close(sockfd);

    return 0;
}

使用UDP实现两个主机间的全双工通信

/*************************************************************************
	> File Name: homework.c
	> Author: yas
	> Mail: rage_yas@hotmail.com
	> Created Time: Wed 06 Mar 2024 06:09:58 PM CST
 ************************************************************************/

#include<stdio.h>
#include "head.h"
struct cilent
{
    char name[32];
    char text[1024];
};

struct cilent mycilent;
struct cilent youcilent;

void *pthreadSend(void *arg)
{
    int sockid = 0;
    struct sockaddr_in recvaddr;
    int nret = 0;

    sockid = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockid == -1)
    {
        perror("fail to socket");
        return NULL;
    }
    
    recvaddr.sin_family = AF_INET;
    recvaddr.sin_port = htons(50000);
    recvaddr.sin_addr.s_addr = inet_addr("192.168.1.152");

    scanf("%s", mycilent.name);
    nret = sendto(sockid, mycilent.name, sizeof(mycilent.name), 0, (struct sockaddr *)&recvaddr, sizeof(recvaddr));
    if (nret == -1)
    {
        perror("fail to sendto");
        return NULL;
    }

    while(1)
    {
        memset(mycilent.text, 0, sizeof(mycilent.text));
        scanf("%s", mycilent.text);
        nret = sendto(sockid, mycilent.text, sizeof(mycilent.text), 0, (struct sockaddr *)&recvaddr, sizeof(recvaddr));
        if (nret == -1)
        {
            perror("fail to sendto");
            return NULL;
        }

        if(strcmp(mycilent.text, ".quit") == 0)
        {
            break;
        }
    }

    close(sockid);
}

void *pthreadRecv(void *argv)
{
    int sockid = 0;
    struct sockaddr_in recvaddr;
    struct sockaddr_in getaddr;
    socklen_t addlen = sizeof(getaddr);
    int nret = 0;

    sockid = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockid == -1)
    {
        perror("fail to socket");
        return NULL;
    }
    
    recvaddr.sin_family = AF_INET;
    recvaddr.sin_port = htons(50000);
    recvaddr.sin_addr.s_addr = inet_addr("192.168.1.174");
    
    bind(sockid, (struct sockaddr *)&recvaddr, sizeof(recvaddr));

    nret = recvfrom(sockid, youcilent.name, sizeof(youcilent.name), 0, (struct sockaddr *)&getaddr, &addlen);
    if (nret == -1)
    {
        perror("fail to sendto");
        return NULL;
    }

    while(1)
    {
        memset(youcilent.text, 0, sizeof(youcilent.text));
        nret = recvfrom(sockid, youcilent.text, sizeof(youcilent.text), 0, (struct sockaddr *)&getaddr, &addlen);
        if (nret == -1)
        {
            perror("fail to sendto");
            return NULL;
        }

        printf("%s(%s:%d)>%s\n", youcilent.name, inet_ntoa(getaddr.sin_addr), ntohs(getaddr.sin_port), youcilent.text);
        if(strcmp(youcilent.text, ".quit") == 0)
        {
            break;
        }
    }
    close(sockid);
}

int main(void)
{
    pthread_t Send;
    pthread_t Recv;

    pthread_create(&Send, NULL, pthreadSend, NULL);
    pthread_create(&Recv, NULL, pthreadRecv, NULL);

    pthread_join(Send, NULL);
    pthread_join(Recv, NULL);



    return 0;
}

使用线程实现并行收发

  • 11
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值