【嵌入式学习】网络通信基础-Day3&4&5-多点通信&域套接字,IO模型分类

D3&D4.TCP并发服务器&多点通信&域套接字

作业

1> 将广播、组播、流式域套接字、报式域套接字各实现一遍

2> 完成TFTP文件传输作业
tftp.c

#include "tftp.h"

int blocksize = DATA_SIZE;

int tftp_download()
{
    int log_fp = -1;
    log_fp = open("./log.txt", O_WRONLY | O_CREAT | O_TRUNC, 0664);
    if (log_fp == -1)
    {
        perror("创建文件失败:");
        return -1;
    }

    // 1、创建用于通信的套接字文件描述符
    int cfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (cfd == -1)
    {
        perror("socket error");
        return -1;
    }

    // 输入文件名
    printf("请输入要拷贝的文件名:");
    char filename[128];
    fgets(filename, sizeof(filename), stdin);
    filename[strlen(filename) - 1] = '\0';

    // 创建文件
    int fd_cp = -1;
    fd_cp = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664);

    if (fd_cp == -1)
    {
        perror("创建文件失败:");
        return -1;
    }

    // 2、绑定(可选)
    // 3、填充服务器的地址信息结构体
    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(SER_PORT);
    sin.sin_addr.s_addr = inet_addr(SER_IP);

    // 向服务器发送下载请求
    char send_buf[516] = "";

    // 组装请求数据
    short *p1 = (short *)send_buf;
    *p1 = htons(1);

    char *p2 = send_buf + 2;
    strcpy(p2, &filename[0]);
    char *p3 = p2 + strlen(p2) + 1;
    strcpy(p3, "octet");
    int len = 4 + strlen(p2) + strlen(p3); // 要发送的长度
    // 向服务器发送请求
    sendto(cfd, send_buf, len, 0, (struct sockaddr *)&sin, sizeof(sin));
    char rbuf[1024] = "";
    int res = 0;
    short *block_count = (short *)(send_buf + 2);

    char log_buf[1024] = "";

    short num = 1;

    socklen_t addrlen = sizeof(sin);

    while (1) // res == 512
    {
        bzero(rbuf, 1024);
        res = recvfrom(cfd, rbuf, sizeof(rbuf), 0, (struct sockaddr *)&sin, &addrlen);
        printf("res=%d\n", res);
        if (ntohs(*((short *)rbuf)) == 5)
        {
            printf("ERROR:\n");
            printf("[ERROR_CODE]:%d\n", ntohs(*((short *)(rbuf + 2))));
            printf("[ERROR_MSG]:%s\n", rbuf + 4);
        }
        else if (ntohs(*((short *)rbuf)) == 3)
        {
            printf("收到了数据包\n");
            // write(fd_cp, rbuf + 4, res - 4);
            if (num == ntohs(*((short *)(rbuf + 2))))
            {
                write(fd_cp, rbuf + 4, res - 4);

                // 返回ACK
                *p1 = htons(4);
                *block_count = htons(num);
                if (sendto(cfd, send_buf, 4, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
                {
                    perror("sendto error:");
                    return -1;
                }
                write(log_fp, send_buf, 4);
                printf("返回了ACK\n");
                printf("block_count=%d\n", ntohs(*block_count));
                num++;
            }
        }

        if (res < 516)
        {
            printf("接收结束!\n");
            break;
        }
    }

    // //5、关闭套接字
    close(cfd);
    close(fd_cp);
    return 0;
}

int tftp_update()
{
    struct tftp_packet rcv_packet, snd_packet;
    // 输入文件名
    printf("请输入要上传的文件名:");
    char filename[128];
    fgets(filename, sizeof(filename), stdin);
    filename[strlen(filename) - 1] = '\0';

    int fd = -1;
    fd = open(filename, O_RDONLY);
    if (fd == -1)
    {
        perror("open error");
        return -1;
    }

    // 1、创建用于通信的套接字文件描述符
    int cfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (cfd == -1)
    {
        perror("socket error");
        return -1;
    }

    snd_packet.cmd = htons(CMD_WRQ);
    sprintf(snd_packet.filename, "%s%c%s%c%d%c", filename, 0, "octet", 0, blocksize, 0);
    // 2、绑定(可选)
    // 3、填充服务器的地址信息结构体
    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(SER_PORT);
    sin.sin_addr.s_addr = inet_addr(SER_IP);
    socklen_t addrlen = sizeof(sin);
    sendto(cfd, &snd_packet, sizeof(struct tftp_packet), 0, (struct sockaddr *)&sin, addrlen);

    while (1)
    {
        
    }
    

}

tftp.h

#ifndef _TFTP_H_
#define _TFTP_H_

#include "header.h"

#define SER_PORT 69
#define SER_IP "192.168.117.1"

#define CMD_RRQ (short)1
#define CMD_WRQ (short)2
#define CMD_DATA (short)3
#define CMD_ACK (short)4
#define CMD_ERROR (short)5
#define CMD_LIST (short)6
#define CMD_HEAD (short)7

#define DATA_SIZE 512

struct tftp_packet
{
    __u_short cmd;
    union
    {
        __u_short code;
        __u_short block;
        // For a RRQ and WRQ TFTP packet
        char filename[2];
    };
    char data[DATA_SIZE];
};

struct tftp_request
{
    int size;
    struct sockaddr_in client;
    struct tftp_packet packet;
};

int tftp_download();
int tftp_update();

#endif

D5.IO模型分类

作业

1> 使用select实现TCP客户端的并发

2> 使用poll实现TCP服务器的并发

你可能感兴趣的:(学习,数据库,网络)