学习嵌入式第三十五天

文章目录

网络(续上)

1.函数接口

  • sendto

    tex 复制代码
    原型: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
    	dest_addr:指向一个sockaddr结构体
    	addrlen:指向的结构体的长度
    返回值:
    	成功返回实际发送的字节数
    	失败返回-1
  • recvfrom

    tex 复制代码
    原型: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:输出参数,一般为NULL,不为NULL时,函数将发送方的地址信息填充到这个结构体中
    	addrlen:输入输出参数
    		输入时:必须指向一个整数,大小为src_addr缓冲区的大小
    		输出时:函数会修改这个整数,并将其设置为src_addr中实际存储的地址信息的真实长度
    返回值:
    	成功返回接收到的字节数
    	失败返回-1

2.相关功能实现

1.TCP连接

  • 客户端连接

    c 复制代码
    int tcp_client_connect(char const *ip,char const *port){
    
        int fd = socket(AF_INET,SOCK_STREAM,0);//创建一个TCP套接字
    
        if(fd < 0){
    
            perror("socket fail");
            return -1;
        }//创建失败
    
        struct sockaddr_in seraddr;
    	memset(&seraddr,0,sizeof(seraddr));//初始化服务器地址结构体
        seraddr.sin_family = AF_INET;
        seraddr.sin_port = htons(atoi(port));//设置端口号
        seraddr.sin_addr.s_addr = inet_addr(ip);//输入自己的IP
    /*尝试连接到服务器,失败返回-1,成功返回套接字描述符*/
        if(connect(fd,(const struct sockaddr *)&seraddr,sizeof(seraddr)) < 0){
    
            perror("connect fail");
            return -1;
        }
    
        return fd;
    }
  • 服务器连接

    c 复制代码
    int tcp_accept(char const *ip,char const *port){
    
        int fd = socket(AF_INET,SOCK_STREAM,0);//创建一个TCP套接字
    
        if(fd < 0){
    
            perror("socket fail");
            return -1;
        }//创建失败
        res_fd[0] = fd;
        printf("fd = %d\n",fd);
    
        struct sockaddr_in seraddr;
    
        memset(&seraddr,0,sizeof(seraddr));//初始化服务器地址结构体
    
        seraddr.sin_family = AF_INET;
        seraddr.sin_port = htons(atoi(port));//设置端口
        seraddr.sin_addr.s_addr = inet_addr(ip);//设置IP
    /*绑定套接字到指定的IP和端口*/
        if(bind(fd,(const struct sockaddr *)&seraddr,sizeof(seraddr)) < 0){
    
            perror("connect fail");
            return -1;
        }
    /*监听端口,准备接受连接*/
        if(listen(fd,5) < 0){
    
            perror("listen fail");
            return -1;
        }
    /*接受一个客户端的连接,并返回连接的文件描述符*/
        int connfd = accept(fd,NULL,NULL);
    
        if(connfd < 0){
    
            perror("accept fail");
            return -1;
        }
        res_fd[1] = connfd;
        return connfd;
    }

2.UDP

  • 客户端向服务器端发送消息,服务器端回复收到

    • 客户端

      c 复制代码
      int main(){
      
          // 创建 UDP 套接字
          int clifd = socket(AF_INET,SOCK_DGRAM,0);
          if(clifd < 0){
              perror("socket fail"); // 创建失败,输出错误信息
              return -1;
          }
      
          // 定义并初始化服务器地址结构体
          struct sockaddr_in seraddr;
          memset(&seraddr,0,sizeof(seraddr));
          seraddr.sin_family = AF_INET; // IPv4
          seraddr.sin_port = htons(50000); // 端口号50000,转为网络字节序
          seraddr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 服务器IP
      
          // 主循环,不断发送和接收消息
          while(1){
              char buf[1024] = {0}; // 发送缓冲区
              // 从标准输入读取一行数据
              fgets(buf,sizeof(buf),stdin);
              // 发送数据到服务器,包含字符串结束符
              int ret = sendto(clifd,buf,strlen(buf)+1,0,(const struct sockaddr*)&seraddr,sizeof(seraddr));
      
              char rbuf[1024] = {0}; // 接收缓冲区
              // 接收服务器返回的数据
              recvfrom(clifd,rbuf,sizeof(rbuf)+1,0,NULL,NULL);
              // 打印服务器返回的数据
              printf("buf = %s\n",rbuf);
              // 清空接收缓冲区
              memset(rbuf,0,sizeof(rbuf));
          }
      
          return 0;
      }
    • 服务器端

      c 复制代码
      int main(){
      
          // 创建 UDP 套接字
          int serfd = socket(AF_INET,SOCK_DGRAM,0);
          if(serfd < 0){
              perror("socket fail"); // 创建失败,输出错误信息
              return -1;
          }
      
          // 定义并初始化服务器地址结构体
          struct sockaddr_in seraddr;
          memset(&seraddr,0,sizeof(seraddr));
          seraddr.sin_family = AF_INET; // IPv4
          seraddr.sin_port = htons(50000); // 端口号50000,转为网络字节序
          seraddr.sin_addr.s_addr = INADDR_ANY; // 监听所有网卡
      
          // 绑定套接字和地址
          if(bind(serfd,(const struct sockaddr *)&seraddr,sizeof(seraddr)) < 0){
              perror("fail to bind"); // 绑定失败,输出错误信息
              return -1;
          }
      
          // 主循环,不断接收和回复客户端消息
          while(1){
              char buf[1024]; // 接收缓冲区
              struct sockaddr_in cliaddr; // 客户端地址结构体
              socklen_t len = sizeof(cliaddr); // 地址长度
      
              // 接收客户端消息,获取客户端地址
              int ret = recvfrom(serfd,buf,sizeof(buf),0,(struct sockaddr*)&cliaddr,&len);
      
              // 打印接收到的字节数
              printf("ret = %d \n",ret);
              printf("--------------------------\n");
              // 打印客户端IP地址
              printf("cliaddr = %s\n",inet_ntoa(cliaddr.sin_addr));
              // 打印客户端端口号
              printf("cliport = %d\n",ntohs(cliaddr.sin_port));
              printf("--------------------------\n");
      
              // 构造回复消息
              char sbuf[1024] = {0};
              sprintf(sbuf,"recv:%s",buf);
              // 发送回复消息给客户端
              sendto(serfd,sbuf,strlen(sbuf)+1,0,(struct sockaddr*)&cliaddr,sizeof(cliaddr));
              // 清空发送缓冲区
              memset(sbuf,0,sizeof(sbuf));
          }
      
          return 0;
      }

习题

1.客户端向服务器端发送一个文件名,服务器将文件内容打包发给客户端

  • 客户端

    c 复制代码
    int main(){
        int clifd = socket(AF_INET,SOCK_DGRAM,0);
        if(clifd < 0){
    
            perror("socket fail");
            return -1;
        }
    
        struct sockaddr_in seraddr;
        memset(&seraddr,0,sizeof(seraddr));
    
        seraddr.sin_family = AF_INET;
        seraddr.sin_port = htons(50000);
        seraddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    
        msg_t msg;
        msg.type = -1;
    
        fgets(msg.buf,sizeof(msg.buf),stdin);
        msg.buf[strlen(msg.buf)-1] = '\0';
        sendto(clifd,msg.buf,sizeof(msg.buf),0,(const struct sockaddr*)&seraddr,sizeof(seraddr));
    
        int fd = open(msg.buf,O_WRONLY|O_TRUNC|O_CREAT,0666);
        if(fd < 0){
    
            perror("fail to open file");
            return -1;
        }
        int n = 0;
        while((n = recvfrom(clifd,&msg,sizeof(msg),0,NULL,NULL)) > 0){
    
            if(msg.type == 0){
    
                break;
            }
            write(fd,msg.buf,msg.type);
            memset(&msg,0,sizeof(msg));
        }
    
    close(fd);
    close(clifd);
    return 0;
    }
  • 服务器端

    c 复制代码
    int main(){
    
        int serfd = socket(AF_INET,SOCK_DGRAM,0);
        if(serfd < 0){
    
            perror("socket fail");
            return -1;
    
        }
        struct sockaddr_in seraddr;
        memset(&seraddr,0,sizeof(seraddr));
    
        seraddr.sin_family = AF_INET;
        seraddr.sin_port = htons(50000);
        seraddr.sin_addr.s_addr = INADDR_ANY;
    
        if(bind(serfd,(const struct sockaddr *)&seraddr,sizeof(seraddr)) < 0){
    
            perror("fail to bind");
            return -1;
        }
    
        DIR *dir;
        struct dirent *dp;
        msg_t msg;
        struct sockaddr_in cliaddr;
        socklen_t len = sizeof(cliaddr);
    
        dir = opendir("/home/linux/桌面");
        if(dir == NULL){
            perror("fail to open dir");
            return -1;
        }
        recvfrom(serfd,msg.buf,sizeof(msg.buf),0,(struct sockaddr*)&cliaddr,&len);
    
        printf("buf = %s\n",msg.buf);
        while(1){
    
            dp = readdir(dir);
            if(dp == NULL){
    
                perror("fail to read dir");
                return -1;
            }
            else if('.' == dp->d_name[0]){
    
                continue;
            }
            else if(strcmp(dp->d_name,msg.buf) == 0){
    
                sprintf(msg.buf,"/home/linux/桌面/%s",dp->d_name);
                int fd = open(msg.buf,O_RDONLY);
                if(fd < 0){
    
                    perror("fail to open file");
                    return -1;
                }
                int n;
                while((n = read(fd,msg.buf,sizeof(msg.buf))) > 0){
    
                    msg.type = n;
                    sendto(serfd,&msg,sizeof(msg),0,(const struct sockaddr*)&cliaddr,sizeof(cliaddr));
                }
                msg.type = 0;
                sendto(serfd,&msg,sizeof(msg),0,(const struct sockaddr*)&cliaddr,sizeof(cliaddr));
    
                close(fd);
                break;
            }
        }
    
    closedir(dir);
    close(serfd);
    return 0;
    }

2.用UDP实现服务器端和客户端的点对点聊天

  • 客户端

    C 复制代码
    int clifd;
    struct sockaddr_in seraddr;
    socklen_t len = sizeof(seraddr);
    
    void *thread1(void* arg){
        char buf[1024];
        while(1){
    
            memset(buf,0,sizeof(buf));
            recvfrom(clifd,buf,sizeof(buf),0,(struct sockaddr*)&seraddr,&len);
    
            if(strcmp(buf,".quit") == 0){
    
                printf("server quit\n");
                break;
            }
            printf("server say:%s\n",buf);
        }
    
        return NULL;
    }
    void *thread2(void* arg){
    
        char buf[1024];
        while(1){
    
            memset(buf,0,sizeof(buf));
            fgets(buf,sizeof(buf),stdin);
            if(strcmp(buf,".quit\n") == 0){
    
                break;
            }
            sendto(clifd,buf,strlen(buf)+1,0,(struct sockaddr*)&seraddr,sizeof(seraddr));
        }
        return NULL;
    }
    
    int main(){
    
        clifd = socket(AF_INET,SOCK_DGRAM,0);
        if(clifd < 0){
    
            perror("fail to socket");
            return -1;
        }
        memset(&seraddr,0,sizeof(seraddr));
    
        seraddr.sin_family = AF_INET;
        seraddr.sin_port = htons(50000);
        seraddr.sin_addr.s_addr = inet_addr("127.0.0.1");
        
        pthread_t pid1;
        pthread_t pid2;
        void *(*p1)(void*) = thread1;
        void *(*p2)(void*) = thread2;
    
        pthread_create(&pid1,NULL,p1,NULL);
        pthread_create(&pid2,NULL,p2,NULL);
    
        pthread_join(pid1,NULL);
        pthread_join(pid2,NULL);
    
        close(clifd);
        
    
        return 0;
    }
  • 服务器端

    c 复制代码
    int serfd;
    struct sockaddr_in seraddr;
    
    struct sockaddr_in cliaddr;
    socklen_t len = sizeof(cliaddr);
    
    void *thread1(void* arg){
        char buf[1024];
        while(1){
    
            memset(buf,0,sizeof(buf));
            recvfrom(serfd,buf,sizeof(buf),0,(struct sockaddr*)&cliaddr,&len);
    
            if(strcmp(buf,".quit") == 0){
    
                printf("client quit\n");
                break;
            }
            printf("client say:%s\n",buf);
        }
    
        return NULL;
    }
    void *thread2(void* arg){
    
        char buf[1024];
        while(1){
    
            memset(buf,0,sizeof(buf));
            fgets(buf,sizeof(buf),stdin);
            if(strcmp(buf,".quit\n") == 0){
    
                break;
            }
            sendto(serfd,buf,strlen(buf)+1,0,(struct sockaddr*)&cliaddr,len);
        }
        return NULL;
    }
    
    int main(){
    
        serfd = socket(AF_INET,SOCK_DGRAM,0);
        if(serfd < 0){
    
            perror("fail to socket");
            return -1;
        }
        memset(&seraddr,0,sizeof(seraddr));
    
        seraddr.sin_family = AF_INET;
        seraddr.sin_port = htons(50000);
        seraddr.sin_addr.s_addr = INADDR_ANY;
    
        if(bind(serfd,(const struct sockaddr*)&seraddr,sizeof(seraddr))< 0){
    
            perror("fail to bind");
            return -1;
        }
    
    
        
    
        pthread_t pid1;
        pthread_t pid2;
        void *(*p1)(void*) = thread1;
        void *(*p2)(void*) = thread2;
    
        pthread_create(&pid1,NULL,p1,NULL);
        pthread_create(&pid2,NULL,p2,NULL);
    
        pthread_join(pid1,NULL);
        pthread_join(pid2,NULL);
    
        close(serfd);
    
    
        return 0;
    }