您现在的位置是:首页 >其他 >Linux 学习记录31(网络编程篇)网站首页其他

Linux 学习记录31(网络编程篇)

轻指弹 2024-10-04 12:01:05
简介Linux 学习记录31(网络编程篇)

Linux 学习记录31(网络编程篇)

在这里插入图片描述

一、UDP中的connect函数

udp中也可以使用connect函数

  1. TCP中的connect函数会连接服务器,产生三次握手,将服务器和客户端连接起来。
  2. UDP中的connect不会产生连接,仅仅是将对端的IP和端口号记录到内核套接字中此时UDP只能与记录的对端进行通信
  3. 记录后只能与记录的端口和IP进行通信
  4. TCP中这个函数只能成功一次,代表连接服务器
  5. 而在UDP中这个函数可以成功多次,前一次写入的端口和IP会被后一次的覆盖
  6. 若想清空内核数据,只要将sa_family 改成AF_UNSPEC,来清空内核中对端的内核信息
  7. 当UDP采用他connect方式手法数据后recvfrom后面参数改为NULL,sendof后面参数改为,NULL和0;

UDP调用connect的优点

  1. 提升传输效率
  1. 不调用:将对端的信息填充到内核->发送报文->清空内核信息->将对端的信息填充到内核->发送报文->清空内核信息
  2. 调用:将对端的信息填充到内核->发送报文->发送报文->发送报文->清空内核信息
  1. 增加传输稳定性
  1. 调用connet的udp通信,可以防止AB进程在传输数据的过程中收到C的数据,造成数据错误

1. 绑定客户端

struct sockaddr_in dstaddr;
dstaddr.sin_family = AF_INET;
/*记录指定的端口号和IP*/
dstaddr.sin_port = htons(6666);
dstaddr.sin_addr.s_addr = inet_addr("192.168.2.56");
if(connect(sfd, (struct sockaddr *)&dstaddr, sizeof(dstaddr)) == -1)
{/*记录IP和端口号到套接字内核中*/
    ERR_MSG("connect");
    return -1;
}//记录完成后将只能接收来自记录的IP和端口的数据

2. 解绑客户端

struct sockaddr_in dstaddr;
dstaddr.sin_family = AF_UNSPEC;//清空内核中对端的内核信息
if(connect(sfd, (struct sockaddr *)&dstaddr, sizeof(dstaddr)) == -1)
{/*记录IP和端口号到套接字内核中*/
    ERR_MSG("connect");
    return -1;
}//记录完成后将只能接收来自记录的IP和端口的数据

二、(扩展)直接读取键盘值

1. 找到键盘的驱动文件

目录:

在这里插入图片描述

2. 找到使用的键盘的驱动文件

sudo cat event文件
"当打开文件后操作键盘如果看到有数据读出就是该键盘对应的文件"

在这里插入图片描述

3. 读取文件

由于文件在根目录,所以运行程序需要+sudo

//打开键盘驱动文件
int fd = open("/dev/input/event1", O_RDONLY);
if(fd < 0)
{
   ERR_MSG("open");
   return -1;
}
printf("open success fd=%d
", fd);

//读取键盘驱动文件中的数据, /dev/input/event1 
struct input_event ev;

while(1)
{
   if(read(fd, &ev, sizeof(ev)) <= 0)
   {
       ERR_MSG("read");
       return -1;
   }
   printf("ev.type:%u  ev.code:%u   ev.value:%d
", ev.type, ev.code, ev.value);
}

练习通过Tfpd32软件的文件上传与下载

1. main.c

#include "public.h"

int main(int argc, char const *argv[])
{
    int menu_num = 0;
    int power = 1;
    time_t sys_t = time(NULL);
    struct tm *fomattime = localtime(&sys_t);
    char time_str[50] = {0};

    char buf1[50] = {0};
    char buf2[50] = {0};
    char ch1 = 0;
    int back = 0;

    umask(0);
    /*发送请求*/
    // send_request(RD,"file01i1.txt","octet");

    /*创建报式套接字*/
    int sfd = socket(AF_INET, SOCK_DGRAM, 0);
    printf("创建报式套接字...
");
    if(sfd < 0)
    {//如果创建失败则
        ERR_MSG("socket");
        return -1;
    }
    printf("创建成功
");

    /*允许端口被快速重用*/
    int reuse = 1;
    if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse)))
    {
        ERR_MSG("setsockopt");
        return -1;
    }

    /*绑定绑定服务器IP和端口到文件描述付*/
    struct sockaddr_in cin_addr;
    char server_IP[20] = "192.168.2.54";//存储服务器IP
    int server_port = 69;//存储服务器端口
    cin_addr.sin_family = AF_INET;
    printf("input server IP : %s
", server_IP);
    // fgets(server_IP, sizeof(server_IP),stdin);//获取服务器IP
    printf("input server port : %d
", server_port);
    // scanf("%d",&server_port);//获取服务器端口
    cin_addr.sin_addr.s_addr = inet_addr(server_IP);
    cin_addr.sin_port = htons(server_port);

    /*接收消息*/
    socklen_t cin_len = sizeof(cin_addr);
    char str[128];
    char buf[128];
    int res = 0;
    printf("客户端已打开
");
    while(power)
    {
        printf("请选择你的功能:
");
        menu();
        scanf("%d",&menu_num);
        switch(menu_num)
        {
            case 1:{
                printf("请输入需要下载的文件名: ");
                scanf("%s",buf1);
                printf("是否将下载的文件重命名[y/n]: ");
                scanf("
%c",&ch1);
                if(ch1 == 'y')
                {
                    printf("请输入重命名的文件名: ");
                    scanf("
%s",buf2);
                    printf("下载文件:%s----->%s
",buf1,buf2);
                    back = down_load(buf1,buf2,sfd,cin_addr);
                }else if(ch1 == 'n')
                {
                    printf("下载文件:%s----->%s
",buf1,buf1);
                    back = down_load(buf1,NULL,sfd,cin_addr);
                }

                if(back == 0)
                {
                    printf("下载完成
");
                }else if(back == -1)
                {
                    printf("下载失败
");
                }
            }break;

            case 2:{
                printf("是否查看文件库目录[y/n]
");
                scanf("
%c",&ch1);
                if(ch1 == 'y') view_file_lib();
                printf("请输入要上传的文件
");
                scanf("
%s",buf1);
                printf("是否将上传后的文件重命名[y/n]: ");
                scanf("
%c",&ch1);
                if(ch1 == 'y')
                {
                    printf("请输入重命名的文件名: ");
                    scanf("
%s",buf2);
                    printf("上传文件:%s----->%s
",buf1,buf2);
                    back = up_load(buf1,buf2,sfd,cin_addr);
                }else if(ch1 == 'n')
                {
                    printf("上传文件:%s----->%s
",buf1,buf1);
                    back = up_load(buf1,NULL,sfd,cin_addr);
                }
                if(back == 0)
                {
                    printf("上传完成
");
                }else if(back == -1)
                {
                    printf("上传失败
");
                }
            }break;

            // case 3:{
            //     printf("查看文件库
");
            //     system(FILE_LIB);
            // }break;

            case 3:{
                printf("退出客户端
");
                power = 0;
            }break;

            default:{
                printf("请重新输入
");
            }break;
        }
    }
    close(sfd);
    
    return 0;
}

2. public.h

#ifndef __PUBLIC_H_
#define __PUBLIC_H_

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>

#include <fcntl.h>
#include <dirent.h>

#include <pthread.h>
#include <semaphore.h>
#include <signal.h>

#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>

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

#define R O_RDONLY
#define W O_WRONLY|O_CREAT|O_TRUNC
#define A O_WRONLY|O_CREAT|O_APPEND
#define Rp O_RDWR
#define Wp O_RDWR|O_CREAT|O_TRUNC
#define Ap O_RDWR|O_CREAT|O_APPEND

#define IP "192.168.2.52"
#define PORT 8080
#define BACKLOG 128

#define RD 0x01
#define WR 0x02
#define FILE_LIB "./file_lib/" //当前目录下的文件库

/*输入打印的错误类型 打印错误信息,行,具体函数*/
#define ERR_MSG(msg) do{
    fprintf(stderr, "Line:%d :%s %s
",__LINE__, __FILE__,__func__);
    perror(msg);
}while(0)
/*获取时间戳*/
#define GET_TIME(str) do{
    time_t sys_t = time(NULL);
    struct tm *fomattime = localtime(&sys_t);
    sprintf(str,"[%.4d-%.2d-%.2d %.2d:%.2d:%.2d]",
    fomattime->tm_year+1900,fomattime->tm_mon+1,fomattime->tm_mday,
    fomattime->tm_hour,fomattime->tm_min,fomattime->tm_sec);
}while(0)

#pragma pack(1) //设置默认对齐系数 :() 中的参数只能填2^n (n=0,1,2,3,4,5......)

typedef struct
{
    int num;//包编号
    int buf_len;//包长
    char buf_data[1024];//包数据
    
}a;

/*选项菜单*/
void menu(void);
/*发送请求*/
void send_request(char Opcode,const char* file_nume,const char* mode,int sfd,struct sockaddr_in cin_addr);
/*下载*/
int down_load(const char* file_name,const char* new_name,int sfd,struct sockaddr_in cin_addr);
/*查看文件文件库*/
void view_file_lib(void);
/*上传*/
int up_load(const char* file_name,const char* new_name,int sfd,struct sockaddr_in cin_addr);

#endif

3. public.c

#include "public.h"

/*应答,0-1:操作码,固定4,2-3:块编号*/
uint8_t ACK[4] = {0X00,0X04,0X00,0X00};

/*选项菜单*/
void menu(void)
{
    printf("**************************************
");
    printf("1. 下载文件 | 2. 上传文件 | 3.退出客户端|
");
    printf("**************************************
");
}

/*发送请求*/
void send_request(char Opcode,const char* file_nume,const char* mode,int sfd,struct sockaddr_in cin_addr)
{
    uint8_t buf[128] = {0};//发送数据缓存
    int len = strlen(file_nume);
    socklen_t cin_len = sizeof(cin_addr);

    buf[0] = 0x00;
    buf[1] = Opcode;//操作码
    strcpy(buf+2,file_nume);//文件名
    len+=2;
    buf[len++] = 0x00;//''
    strcpy(buf+len,mode);//文件名
    len += strlen(mode);//模式
    buf[len++] = 0x00;//''

    if(sendto(sfd,buf,len,0,(struct sockaddr*)&cin_addr,cin_len) == -1)
    {
        ERR_MSG("sendto");
        return;
    }
}

/*下载*/
int down_load(const char* file_name,const char* new_name,int sfd,struct sockaddr_in cin_addr)
{
    char Rx_buf[1024];//接收缓冲区
    char file[50] = {0};//接收缓冲区
    int res = 0;//接收缓冲区
    int file_fd = 0;
    int schedule = 0;//进度

    struct sockaddr_in Tx_addr;//发送端地址信息

    socklen_t cin_len = sizeof(cin_addr);
    socklen_t Tx_len = sizeof(Tx_addr);

    strcat(file,FILE_LIB);

    /*在指定文件夹下创建文件*/
    if(new_name != NULL)
    {
        strcat(file,new_name);
    }else
    {
        strcat(file,file_name);
    }

    /*打开文件*/
    if((file_fd = open(file,Wp,0664)) == -1)
    {
        ERR_MSG("open");
        return -1;
    }
    /*发送请求*/
    send_request(RD,file_name,"octet",sfd,cin_addr);
    ACK[1] = 0x04;
    do
    {
        /*读取数据*/
        if((res = recvfrom(sfd,Rx_buf,sizeof(Rx_buf),0,(struct sockaddr*)&Tx_addr,&Tx_len))== -1)
        {
            ERR_MSG("recvfrom");
            return -1;
        }

        /*如果发现数据包操作码*/
        if(Rx_buf[1] == 0x03)
        {
            
            write(file_fd,Rx_buf+4,res-4);
            ACK[2] = Rx_buf[2];
            ACK[3] = Rx_buf[3];
            if(sendto(sfd,ACK,4,0,(struct sockaddr*)&Tx_addr,Tx_len) == -1)
            {//回应
                ERR_MSG("sendto");
                return-1;
            }
        }
        /*如果发现错码*/
        if(Rx_buf[1] == 0x05)
        {
            printf("Error download[%d]: %s!!!
",Rx_buf[3],Rx_buf+4);
            // system(file);
            return -1;
        }
        printf("
%d",schedule++);
    }while((res-4)==512);
    printf("
");
    return 0;
}

/*查看文件文件库*/
void view_file_lib(void)
{
    DIR* dp;

    if((dp=opendir(FILE_LIB))==NULL)
    {
        perror("opendir: ");
        return ;
    }
    struct dirent* tp;
    while((tp = readdir(dp)) != NULL)
    {
        printf("%s | ",tp->d_name);
    }
    printf("
");
}


/*上传*/
int up_load(const char* file_name,const char* new_name,int sfd,struct sockaddr_in cin_addr)
{
    uint8_t Rx_buf[20];//接收缓冲区
    uint8_t Tx_buf[1024];//接收缓冲区
    uint8_t file[50] = {0};//接收缓冲区
    int res = 0;//接收缓冲区
    int read_num = 0;//接收缓冲区
    int file_fd = 0;
    uint32_t schedule = 1;//进度
    uint8_t piece[2] = {0x00,0x01};//进度

    struct sockaddr_in Tx_addr;//发送端地址信息

    socklen_t cin_len = sizeof(cin_addr);
    socklen_t Tx_len = sizeof(Tx_addr);

    strcat(file,FILE_LIB);

    /*选择指定文件夹下文件*/
    strcat(file,file_name);
    /*打开文件*/
    if((file_fd = open(file,R)) == -1)
    {
        ERR_MSG("open");
        return -1;
    }
    /*发送请求*/
    send_request(WR,file_name,"octet",sfd,cin_addr);
    do
    {
        /*读取数据*/
        if((res = recvfrom(sfd,Rx_buf,sizeof(Rx_buf),0,(struct sockaddr*)&Tx_addr,&Tx_len))== -1)
        {
            ERR_MSG("recvfrom");
            return -1;
        }

        piece[0] = (schedule-1)/256;
        piece[1] = (schedule-1)%256;

        /*如果发现数据包操作码*/
        if(Rx_buf[1] == 0x04 && Rx_buf[2] == piece[0] && Rx_buf[3] == piece[1])
        {
            Tx_buf[0] = 0x00;
            Tx_buf[1] = 0x03;
            Tx_buf[2] = schedule/256;
            Tx_buf[3] = schedule%256;
            read_num = read(file_fd,Tx_buf+4,512);
            if(sendto(sfd,Tx_buf,read_num+4,0,(struct sockaddr*)&Tx_addr,Tx_len) == -1)
            {//回应
                ERR_MSG("sendto");
                return-1;
            }
            schedule++;
        }
        /*如果发现错码*/
        if(Rx_buf[1] == 0x05)
        {
            printf("Error download[%d]: %s!!!
",Rx_buf[3],Rx_buf+4);
            // system(file);
            return -1;
        }
        printf("
%d ",schedule);
    }while(read_num == 512);
    return 0;
}

在这里插入图片描述

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。