使用C语言实现tftp协议的客户端和服务端,并明确定义出操作码
时间: 2024-02-03 14:13:26 浏览: 40
TFTP是一个基于UDP协议的简单文件传输协议,操作码用于区分不同的TFTP操作。以下是TFTP操作码的定义:
1. RRQ(读请求)
2. WRQ(写请求)
3. DATA(数据)
4. ACK(确认)
5. ERROR(错误)
下面分别介绍TFTP客户端和服务端的实现。
TFTP客户端:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#define MAX_BUF_SIZE 1024
void error(char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
if (argc != 4) {
fprintf(stderr, "Usage: %s <server_ip> <filename> <mode>\n", argv[0]);
exit(1);
}
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
error("Error opening socket");
}
struct sockaddr_in serv_addr;
bzero(&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
serv_addr.sin_port = htons(69);
char buf[MAX_BUF_SIZE];
char *mode = "octet";
sprintf(buf, "%c%c%s%c%s%c", 0x00, 0x01, argv[2], 0x00, mode, 0x00);
int n = sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (n < 0) {
error("Error sending request");
}
FILE *fp = fopen(argv[2], "wb");
if (!fp) {
error("Error opening file for writing");
}
int block_num = 0;
int recv_len = 0;
struct sockaddr_in cli_addr;
socklen_t cli_len = sizeof(cli_addr);
while (1) {
bzero(buf, MAX_BUF_SIZE);
n = recvfrom(sockfd, buf, MAX_BUF_SIZE, 0, (struct sockaddr *)&cli_addr, &cli_len);
if (n < 0) {
error("Error receiving data");
}
int opcode = ntohs(*(unsigned short *)buf);
if (opcode == 5) {
char *error_msg = buf + 4;
fprintf(stderr, "Error: %s\n", error_msg);
exit(1);
} else if (opcode == 3) {
int block = ntohs(*(unsigned short *)(buf + 2));
if (block == block_num + 1) {
fwrite(buf + 4, 1, n - 4, fp);
block_num++;
}
sprintf(buf, "%c%c%c%c", 0x00, 0x04, block_num >> 8, block_num & 0xff);
n = sendto(sockfd, buf, 4, 0, (struct sockaddr *)&cli_addr, cli_len);
if (n < 0) {
error("Error sending ACK");
}
if (n < MAX_BUF_SIZE - 4) {
break;
}
}
}
fclose(fp);
close(sockfd);
return 0;
}
```
TFTP服务端:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#define MAX_BUF_SIZE 1024
void error(char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "Usage: %s <directory>\n", argv[0]);
exit(1);
}
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
error("Error opening socket");
}
struct sockaddr_in serv_addr;
bzero(&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(69);
if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
error("Error on binding");
}
char buf[MAX_BUF_SIZE];
struct sockaddr_in cli_addr;
socklen_t cli_len = sizeof(cli_addr);
while (1) {
bzero(buf, MAX_BUF_SIZE);
int n = recvfrom(sockfd, buf, MAX_BUF_SIZE, 0, (struct sockaddr *)&cli_addr, &cli_len);
if (n < 0) {
error("Error receiving request");
}
int opcode = ntohs(*(unsigned short *)buf);
if (opcode == 1) {
char *filename = buf + 2;
char *mode = buf + 2 + strlen(filename) + 1;
if (strcmp(mode, "octet") != 0) {
char *error_msg = "Unsupported mode";
sprintf(buf, "%c%c%c%c%s%c", 0x00, 0x05, 0x00, 0x00, error_msg, 0x00);
sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&cli_addr, cli_len);
continue;
}
char path[1024];
sprintf(path, "%s/%s", argv[1], filename);
int fd = open(path, O_RDONLY);
if (fd < 0) {
char *error_msg = strerror(errno);
sprintf(buf, "%c%c%c%c%s%c", 0x00, 0x05, 0x00, 0x00, error_msg, 0x00);
sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&cli_addr, cli_len);
continue;
}
int block_num = 0;
while (1) {
bzero(buf, MAX_BUF_SIZE);
int n = read(fd, buf + 4, MAX_BUF_SIZE - 4);
if (n < 0) {
error("Error reading file");
}
if (n == 0) {
break;
}
*(unsigned short *)buf = htons(3);
*(unsigned short *)(buf + 2) = htons(block_num + 1);
sendto(sockfd, buf, n + 4, 0, (struct sockaddr *)&cli_addr, cli_len);
while (1) {
bzero(buf, MAX_BUF_SIZE);
n = recvfrom(sockfd, buf, MAX_BUF_SIZE, 0, (struct sockaddr *)&cli_addr, &cli_len);
if (n < 0) {
error("Error receiving ACK");
}
opcode = ntohs(*(unsigned short *)buf);
if (opcode == 4) {
block_num = ntohs(*(unsigned short *)(buf + 2));
if (block_num == (int)(*(unsigned char *)(buf + 1))) {
break;
}
}
}
}
close(fd);
}
}
close(sockfd);
return 0;
}
```