我在C中编写一个tftp服务器,并在终端上使用tftp命令对其进行测试。但是,在大多数情况下,当我尝试发送RRQ时,我会收到以下内容:
tftp> get a.txt
sent RRQ <file=a.txt, mode=netascii>
received ERROR <code=4, msg=>
Error code 1024:
其他重大事件包括:
tftp> get a.txt
sent RRQ <file=a.txt, mode=netascii>
received DATA <block=20334, 512 bytes>
discarded 4 packets
和这一个:这看起来可能正确,但它几乎没有发生。我用来测试它的文本文件是857字节。
sent ACK <block=1>
received DATA <block=1, 512 bytes>
sent ACK <block=1>
received DATA <block=2, 345 bytes>
Received 857 bytes in 0.0 seconds
这是我的代码的一部分 这里缓冲区是一个大小为512的char数组,为了简化代码,我删除了一些错误处理代码 感谢任何可能提供帮助的人
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <cerrno>
//define opcode for later use
enum opcode {
RRQ = 1,
WRQ,
DATA,
ACK,
ERROR
};
void handle_write(struct sockaddr_in * sock_info, char* filename, int BUF_LEN){
//printf("Received write request + %d\n", WRQ);
return;
}
void handle_error(unsigned short int * opcode_ptr, char* buffer, socklen_t sockaddr_len, int server_socket, struct sockaddr_in * sock_info, const char* errormsg){
ssize_t n;
*opcode_ptr = htons(ERROR);
*(opcode_ptr + 1) = htons(1);
*(buffer + 4) = 0;
//memcpy(buffer+4, errormsg, strlen(errormsg));
intr_send:
n = sendto(server_socket, buffer, 5, 0,
(struct sockaddr *)sock_info, sockaddr_len);
if(n < 0) {
if(errno == EINTR) goto intr_send;
perror(errormsg);
exit(-1);
}
return;
}
int main() {
int BUF_LEN = 516;
ssize_t n;
char buffer[BUF_LEN];
socklen_t sockaddr_len;
int server_socket;
struct sigaction act;
unsigned short int opcode;
unsigned short int * opcode_ptr;
struct sockaddr_in sock_info;
memset(&sock_info, 0, sockaddr_len);
//----------setup the server----------------//
sock_info.sin_addr.s_addr = htonl(INADDR_ANY);
sock_info.sin_port = htons(5743);
sock_info.sin_family = PF_INET;
if((server_socket = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket");
exit(-1);
}
sockaddr_len = sizeof(sock_info);
if(bind(server_socket, (struct sockaddr *)&sock_info, sockaddr_len) < 0) {
perror("bind");
exit(-1);
}
getsockname(server_socket, (struct sockaddr *)&sock_info, &sockaddr_len);
printf("UDP server listening on port: %d\n", ntohs(sock_info.sin_port));
//----------setup the server----------------//
while(1){
intr_recv:
n = recvfrom(server_socket, buffer, BUF_LEN, 0, (struct sockaddr *)&sock_info, &sockaddr_len);
if(n < 0) {
if(errno == EINTR) goto intr_recv;
perror("recvfrom()");
exit(-1);
}
opcode_ptr = (unsigned short int *)buffer;
opcode = ntohs(*opcode_ptr); //the opcode will be either RRQ or WRQ according to the test
if(opcode != RRQ && opcode != WRQ) {
/* Illegal TFTP Operation */
handle_error(opcode_ptr, buffer, sockaddr_len, server_socket, &sock_info, "invalid command");
}
else {
if(fork() == 0) {
/* Child - handle the request */
FILE* fd;
char* filename;
filename = strdup(buffer+2); //this is the filename to be read (i.e. a.txt)
printf("request received\n");
char data[512];
//----------------------------------handle read request-------------------------------------//
if(opcode == RRQ){
int blocknumber = 0;
int i = 0; //counter for loop
fd = fopen(filename, "r");
free(filename);
//uint8_t data[512];
ssize_t datalen, n;
int done = 0; //this is a boolean indicator that indicates whether the packet transfering process is done or not.
while(!done){
datalen = fread(data, 1, 512, fd);
blocknumber++;
if(datalen < 512){
done = 1; //according to rfc 1350, the last packet will have a data length less than 512 bytes.
}
//for(i = 5; i > 0; i--){
*opcode_ptr = htons(DATA);
opcode = ntohs(*opcode_ptr);
*(opcode_ptr + 1) = htons(blocknumber);
memcpy(buffer + 4, data, datalen);
buffer[datalen + 4] = '\0';
//*(buffer + 4) = 0;
//printf("%d %s\n", datalen, buffer+2);
n = sendto(server_socket, buffer, 4 + datalen, 0, (struct sockaddr *)&sock_info, sockaddr_len);
if(n < 0){
perror("sendto() failed");
exit(-1);
}
//printf("done %d\n", done);
//char buffer[512];
n = recvfrom(server_socket, buffer, sizeof(buffer), 0, (struct sockaddr *)&sock_info, &sockaddr_len);
opcode_ptr = (unsigned short int *)buffer;
opcode = ntohs(*opcode_ptr);
if(n >= 0 && n < 4){
//handle_error(opcode_ptr, buffer, sockaddr_len, server_socket, &sock_info, "invalid request size");
}
if(n > 4){
break;
}
//}
//if(i != 0){
// printf("Transfer timeout!\n");
// exit(1);
//}
//printf("opcode is %d\n", opcode);
if(opcode == ERROR){
printf("Error received\n");
exit(1);
}
if(opcode != ACK){
printf("Invalid message received\n");
exit(1);
}
}
}
//----------------------------------handle read request-------------------------------------//
//----------------------------------handle write request------------------------------------//
//----------------------------------handle write request------------------------------------//
close(server_socket);
break;
}
else {
/* Parent - continue to wait */
}
}
}
return EXIT_SUCCESS;
}
答案 0 :(得分:0)
我读了你的代码但没有通过执行来测试。
与RFC 1350比较,我找到的是
buffer
是不够的,因为标题没有空间(操作码和块#)。您至少需要4个字节。buffer + 2
从memcpy()
撰写数据。这应该破坏块号。似乎应该使用buffer + 4
。buffer[datalen + 2] = '\0';
不应该被需要。我认为你应该删除它,因为它会破坏数据或导致缓冲区溢出。