利用网络编程实现TFTP协议

编程入门 行业动态 更新时间:2024-10-23 11:24:20

利用<a href=https://www.elefans.com/category/jswz/34/1768814.html style=网络编程实现TFTP协议"/>

利用网络编程实现TFTP协议

一、TFTP(Trivial File Transfer Protocol,简单文件传输协议)是TCP/IP协议族中的一个用来在客户机与服务器之间进行简单文件传输的协议,提供不复杂、开销不大的文件传输服务。

二、程序客户端

        1)对传输文件数据进行加包处理,防止传输粘包

#include "./net.h"
//发送加包之后的数据
int write_socket(int sockfd, char *buf, int size)
{char *str = buf;int count = size;while(count > 0){//得到发送后数据int len = send(sockfd, str, count, 0);if(-1 == len){close(sockfd);}//如果发送数据为0 就继续发送else if(0 == len){continue;}//取新的字符串地址 是在如果发送完size字节后还有数据要发送 就继续发送buf += len;//让传入字节数减去已经发送的字节数count -=len;}//返回发送的字节数return size;
}
//加包处理 一定要为long整型 因为htonl为long型
int sendMsg(int sockfd, char *buf, long len)
{//入参判断if(NULL == buf || len <= 0 || sockfd <= 0){perror("Add Error");return -1;}//动态申请内存空间 数据长度 + 包头 4字节 char *data = (char *)malloc(len+4);//将长度转换为网络字节序 切记一定要为long整型long biglen = htonl(len);//内存拷贝 将biglen内容拷贝至data地址开始后的4个字节内memcpy(data, &biglen, 4);//将读到字符串 拷贝到包(占4字节)后开始地址内memcpy(data+4, buf, len);//发送数据int ret = write_socket(sockfd, data, len+4);//释放内存free(data);data = NULL;return ret;
}

        2)主函数

#include "./net.h"int main(int argc, const char *argv[])
{if(argc != 3){puts("usage:app ip port");return -1;}int sockfd = tcp_connect(argv[1], atoi(argv[2]));int ret = tcp_com(sockfd);if(ret < 0){//关闭socket对象close(sockfd);}return 0;
}

        3)解析字符串,我们主要传输文件例子为:put 1.png# OR get 1.png#

#include "./net.h"int split(char *str, char **cmd, char **filename)
{if(NULL == str){perror("NULL ERROR");return -1;}int j = 1;while(1){//读到命令所在位置if(*str != ' ' && j == 1){*cmd = str;j = 0;}//如果为空格就一直往后跑else if(*str == ' '){str++;}else if(*str != ' ' && j == 0){str++;//截断字符串 读出cmd命令//下面类似if(*str == ' '){*str = '\0';break;}}}//此时str为空格 所以要加一str++;while(1){//读到文件名所在位置if(*str != '#' && j == 0){*filename = str;j = 1;}else if(*str == '#'){*str = '\0';break;}str++;}return 0;
}

        4)主要工作函数 用于上传文件下载文件,已经链接服务器

#include "./net.h"int tcp_com(int sockfd)
{//发送信息char buf[50] = {'\0'};char *cmd = NULL;char *filename = NULL;while(1){//每次置空字符串memset(buf, '\0',sizeof(buf));fgets(buf, sizeof(buf), stdin);//将字符串发送服务器send(sockfd, buf, strlen(buf), 0);//拆分字符串split(buf, &cmd, &filename);printf("cmd = %s filename = %s\n",cmd,filename);//根据命令选择操作order_work(sockfd, cmd, filename);}
}int tcp_connect(const char *ip, int port)
{//创建TPCsocket对像 socektint tcp_socket = socket(AF_INET, SOCK_STREAM, 0);if(tcp_socket < 0){perror("Socket Error");return -1;}puts("Socket OK!");//请求连接struct sockaddr_in server;//协议 IPV_4server.sin_family = AF_INET;//地址号 要转为网络字节序server.sin_port = htons(port);//端口号 转为网络字节序server.sin_addr.s_addr = inet_addr(ip);//连接if(connect(tcp_socket, (struct sockaddr *)&server, sizeof(server)) < 0){perror("Connect Error");return -1;}puts("Connect OK!");return tcp_socket;
}int order_work(int sockfd, char *cmd, char *filename)
{if(NULL == filename || -1 == sockfd){perror("Work Error");return -1;}//上传文件if(strncmp(cmd, "put", 3) == 0){int ret = upload(sockfd, filename);if(ret < 0){perror("Upload Error");return -1;}puts("Upload Success");}//下载文件else if(strncmp(cmd, "get", 3) == 0){int ret = Download(sockfd, filename);if(ret < 0){perror("Download Error");return -1;}puts("Download Success");}
}
//上传文件
int upload(int sockfd, char *filename)
{if(NULL == filename || -1 == sockfd){perror("NULL ERROR");return -1;}//打开文件int fd = open(filename, O_RDONLY, 0666);if(fd < 0){perror("Open Error");return -1;}//获取文件大小 一定要为long 为了防止加包时出错long size = lseek(fd, 0, SEEK_END);//使指针重回文件头lseek(fd, 0, SEEK_SET);//读取文件内容printf("file size:%ld\n",size);//开辟一个空间 存放读到的字符串 +1 为'\0'的空间char *data = (char *)malloc(size+1);int ret = read(fd, data, size);if(ret < 0){perror("Read Error");return -1;}//读完之后将字符串 文件大小发送加包函数进行处理int ret_1 = sendMsg(sockfd, data, size);printf("send data : %d\n",ret_1);//释放空间free(data);data = NULL;return 0;
}
//下载文件 与服务器端一样
int Download(int socketfd, char *filename)
{if(-1 == socketfd || NULL == filename){perror("NULL ERROR");return -1;}//创建文件int fd = open(filename, O_CREAT | O_WRONLY, 0666);if(fd < 0){perror("Download Error");return -1;}//用来存放读到的字符串char *data = NULL;int size = recvMsg(socketfd, &data);//然后写入文件内write(fd, data, size);return 0;
}//解析读到的字符串 解包
int readn(int socketfd, char *buf, int size)
{char *str = buf;int count = size;int len = 0;while(count > 0){len = recv(socketfd, str, count, 0);if(-1 == len){return -1;}else if(0 == len){return size - count;}str += len;count -= len;}//返回读到的字节数return size;
}int recvMsg(int socketfd, char **msg)
{//接收数据//读数据头 因为ntohl为long型long len = 0;//先读4字节 首先解读到包里面 存放的文件大小readn(socketfd, (char *)&len, 4);len = ntohl(len);printf("file size:%ld\n",len);//根据读出的长度分配内存, +1 存储'\0'char *buf = (char *)malloc(len+1);//然后根据解读到包里面文件的大小 读取多少数据int ret = readn(socketfd, buf, len);if(ret != len){close(socketfd);free(buf);puts("Recv Error");return -1;}buf[len] = '\0';//读到的字符串给参数*msg = buf;return ret;
}

        5)头文件

#ifndef _NET_H_
#define _NET_H_#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>//发送数据
int write_socket(int sockfd, char *buf, int size);
//拆分字符串 获取命令
int split(char *str, char **cmd, char **filename);
//tcp 连接获取socket
int tcp_connect(const char *ip, int port);
//tcp 通信
int tcp_com(int sockfd);
//根据解析的命令操作
int order_work(int sockfd, char *cmd, char *filename);
//上传文件
int upload(int sockfd, char *filename);
//加包处理
int sendMsg(int sockfd, char *buf, long len);
//下载文件
int Download(int socketfd, char *filename);
//首先解包 获取文件大小 然后读取数据
int readn(int socketfd, char *buf, int size);
//接受数据
int recvMsg(int socketfd, char **msg);
#endif

三、程序服务端

        1)主函数

#include "./net.h"int main(int argc, const char *argv[])
{if(argc != 3){puts("Usage:app ip port");return -1;}//获得监听的socket对象int listenfd = tcp_server(argv[1], atoi(argv[2]));//接受连接 accept()int newfd = 0;struct sockaddr_in client;memset(&client, '\0', sizeof(client));int len = sizeof(client);newfd = accept(listenfd, (struct sockaddr *)&client, &len);if(newfd < 0){perror("Accept Error");return -1;}puts("Accept OK");//转换为主机字节序 和点分十进制的字符串//ip地址char *ip = inet_ntoa(client.sin_addr);//端口号int port = ntohs(client.sin_port);printf("client ip = %s port = %d\n",ip,port);int ret = tcp_com(newfd);if(ret < 0){close(newfd);}return 0;
}

        2)解析字符串 同客户端一样

#include "./net.h"int split(char *str, char **cmd, char **filename)
{if(NULL == str){perror("NULL ERROR");return -1;}int j = 1;while(1){if(*str != ' ' && j == 1){*cmd = str;j = 0;}else if(*str == ' '){str++;}else if(*str != ' ' && j == 0){str++;if(*str == ' '){*str = '\0';break;}}}str++;while(1){if(*str != '#' && j == 0){*filename = str;j = 1;}else if(*str == '#'){*str = '\0';break;}str++;}return 0;
}

        3)主要操作函数

#include "./net.h"int tcp_com(int socketfd)
{char buf[50] = {'\0'};char *cmd = NULL;char *filename = NULL;while(1){int ret = recv(socketfd, buf, sizeof(buf), 0);if(strncasecmp(buf, "quit", 4) == 0) break;else if(ret == 0) break;split(buf, &cmd, &filename);printf("cmd = %s filename = %s\n",cmd,filename);order_work(socketfd, cmd, filename);}
}int tcp_server(const char *ip, int port)
{//创建tcpSocket对像 socket()int tcp_socket = socket(AF_INET, SOCK_STREAM, 0);if(tcp_socket < 0){perror("Socket Error");return -1;}puts("Socket OK");//绑定自己的IP地址和端口号struct sockaddr_in myAddr;memset(&myAddr, '\0', sizeof(myAddr));//协议 IPV4myAddr.sin_family = AF_INET;//转换为网络字节序//端口号myAddr.sin_port = htons(port);//地址myAddr.sin_addr.s_addr = inet_addr(ip);//套接字绑定信息if(bind(tcp_socket, (struct sockaddr *)&myAddr, sizeof(myAddr)) < 0){//报错要先关闭套接字close(tcp_socket);perror("Bind Error");return -1;}puts("Bind OK");//监听socket 监听连接的客户端//实际可以一下连接6个 5+1if(listen(tcp_socket, 5) < 0){close(tcp_socket);perror("Listen Error");return -1;}puts("Listen OK");return tcp_socket;
}int order_work(int socketfd, char *cmd, char *filename)
{//下载文件if(strncmp(cmd, "put", 3) == 0){int ret = Download(socketfd, filename);if(ret < 0){perror("Download Error");return -1;}puts("Download Success");}//上传文件else if(strncmp(cmd, "get", 3) == 0){int ret = upload(socketfd, filename);if(ret < 0){perror("Upload Error");return -1;}puts("Upload Success");}
}int Download(int socketfd, char *filename)
{if(-1 == socketfd || NULL == filename){perror("NULL ERROR");return -1;}int fd = open(filename, O_CREAT | O_WRONLY, 0666);if(fd < 0){perror("Download Error");return -1;}puts("1");char *data = NULL;int size = recvMsg(socketfd, &data);write(fd, data, size);return 0;
}int readn(int socketfd, char *buf, int size)
{char *str = buf;int count = size;int len = 0;while(count > 0){len = recv(socketfd, str, count, 0);if(-1 == len){return -1;}else if(0 == len){return size - count;}str += len;count -= len;}return size;
}int recvMsg(int socketfd, char **msg)
{//接收数据//读数据头long len = 0;readn(socketfd, (char *)&len, 4);len = ntohl(len);printf("file size:%ld\n",len);//根据读出的长度分配内存, +1 存储'\0'char *buf = (char *)malloc(len+1);int ret = readn(socketfd, buf, len);if(ret != len){close(socketfd);free(buf);puts("Recv Error");return -1;}buf[len] = '\0';*msg = buf;return ret;
}int write_socket(int sockfd, char *buf, int size)
{char *str = buf;int count = size;while(count > 0){int len = send(sockfd, str, count, 0);if(-1 == len){close(sockfd);}else if(0 == len){continue;}buf += len;count -=len;}return size;
}int sendMsg(int sockfd, char *buf, long len)
{if(NULL == buf || len <= 0 || sockfd <= 0){perror("Add Error");return -1;}//动态申请内存空间 数据长度 + 包头 4字节 char *data = (char *)malloc(len+4);//将长度转换为网络字节序long biglen = htonl(len);memcpy(data, &biglen, 4);memcpy(data+4, buf, len);//发送数据int ret = write_socket(sockfd, data, len+4);//释放内存free(data);data = NULL;return ret;
}int upload(int sockfd, char *filename)
{if(NULL == filename || -1 == sockfd){perror("NULL ERROR");return -1;}int fd = open(filename, O_RDONLY, 0666);if(fd < 0){perror("Open Error");return -1;}long size = lseek(fd, 0, SEEK_END);lseek(fd, 0, SEEK_SET);//读取文件内容printf("file size:%ld\n",size);char *data = (char *)malloc(size+1);int ret = read(fd, data, size);if(ret < 0){perror("Read Error");return -1;}int ret_1 = sendMsg(sockfd, data, size);printf("send data : %d\n",ret_1);free(data);data = NULL;return 0;
}

        4)头文件

#ifndef _NET_H_
#define _NET_H_#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>int tcp_server(const char *ip, int port);
int tcp_com(int socketfd);
int split(char *str, char **cmd, char **filename);
int order_work(int socketfd, char *cmd, char *filename);
int Download(int socketfd, char *filename);
int readn(int socketfd, char *buf, int size);
int recvMsg(int socketfd, char **msg);
int write_socket(int sockfd, char *buf, int size);
int sendMsg(int sockfd, char *buf, long len);
int upload(int sockfd, char *filename);
#endif

更多推荐

利用网络编程实现TFTP协议

本文发布于:2023-06-12 05:19:12,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/652075.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:网络编程   协议   TFTP

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!