自己实现一个简单的ftp软件
程序员文章站
2022-04-24 14:57:29
...
近期面试有个机试题是写个ftp软件,自己写完不想就扔了,就放到这里大家参考一下,也帮我优化优化,没什么太难的也就不需要什么注释了
消息格式:
cmd | size | data
服务端:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <dirent.h>
#include <stdlib.h>
#define COMPARE(a, b, c) (strcmp(a, c) b 0)
#define HEAD_SIZE 4
char *packet(int size, const char *data);
int main(int argc, const char *argv[])
{
int sockfd, acceptfd;
struct sockaddr_in myaddr;
memset(&myaddr, 0, sizeof(myaddr));
socklen_t addrlen = sizeof(struct sockaddr_in);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) return -1;
myaddr.sin_family = AF_INET;
myaddr.sin_port = htons(6060);
myaddr.sin_addr.s_addr = inet_addr("192.168.255.128");
int optval = 1;
socklen_t optlen = sizeof(optval);
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, optlen); //设置端口重用
if (bind(sockfd, (struct sockaddr *)&myaddr, addrlen) == -1) {
printf("bind faild\n");
return -1;
}
if (listen(sockfd, 10) == -1) {
printf("listen faild\n");
return -1;
}
if ((acceptfd=accept(sockfd, (struct sockaddr *)&myaddr, &addrlen)) == -1) {
printf("acceptfd faild\n");
return -1;
}
ssize_t recvlen, sendlen;
char buf[256];
DIR *dirfd;
while (1) { //注意服务端使用的消息格式是size|data
recv(acceptfd, buf, 4, 0); //先接收开始的四个字节cmd
if (COMPARE(buf, ==, "get")) {
memset(buf, 0, 0);
recv(acceptfd, buf, 4, 0);
int size = *(int *)buf;
recv(acceptfd, buf, size, 0);
printf("%s\n", buf);
FILE *fp = fopen(buf, "rb");
if (fp == NULL) {
printf("file open failed\n");
break;
}
memset(buf, 0, 0); //使用buf前先清空一下,防止出现其它不想要的字符
size_t readlen = fread(buf, 1, sizeof(buf), fp);
char *tmp = packet(readlen, buf);
send(acceptfd, tmp, HEAD_SIZE+readlen, 0);
free(tmp);
fclose(fp);
} else if (COMPARE(buf, ==, "ls")) {
printf("%s\n", buf);
if ((dirfd = opendir("./")) == NULL) {
char *tmp = packet(8, "no file");
send(sockfd, tmp, HEAD_SIZE + 8, 0);
free(tmp);
printf("file open failed\n");
} else {
struct dirent *pdirent;
while ((pdirent = readdir(dirfd)) != NULL) {
if (pdirent->d_name[0] == '.')
continue;
char *tmp = packet(strlen(pdirent->d_name)+1, pdirent->d_name);
sendlen = send(acceptfd, tmp, HEAD_SIZE + strlen(pdirent->d_name)+1, 0);
if (sendlen == 0) break;
free(tmp);
}
char *tmp = packet(4, "ok");
send(acceptfd, tmp, HEAD_SIZE + 3, 0);
}
} else if (COMPARE(buf, ==, "put")) {
printf("%s\n", buf);
recv(acceptfd, buf, 4, 0);
int size = *(int *)buf;
memset(buf, 0, 0);
size_t recvlen = recv(acceptfd, buf, size, 0);
FILE *fp = fopen("./update.txt", "wb");
if (fp == NULL) {
printf("file open failed\n");
break;
}
fwrite(buf, 1, recvlen, fp);
strcpy(buf, "ok");
send(acceptfd, buf, 3, 0);
fclose(fp);
}
}
close(sockfd);
close(acceptfd);
return 0;
}
char *packet(int size, const char *data) {
char *ret = malloc(sizeof(int) + size);
*(int *)ret = size;
memcpy(ret + HEAD_SIZE, data, size);
return ret;
}
客户端:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#define COMPARE(a, b, c) (strcmp(a, c) b 0)
#define HEAD_SIZE 8
char *packet(const char *cmd, int size, const char *data);
int main(int argc, const char *argv[])
{
int sockfd;
struct sockaddr_in myaddr;
memset(&myaddr, 0, sizeof(myaddr));
socklen_t addrlen = sizeof(struct sockaddr_in);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) return -1;
myaddr.sin_family = AF_INET;
myaddr.sin_port = htons(6060);
myaddr.sin_addr.s_addr = inet_addr("192.168.255.128");
if (connect(sockfd, (struct sockaddr *)&myaddr, addrlen) == -1) {
printf("connect faild\n");
return -1;
}
ssize_t recvlen, sendlen;
char buff[256];
char send_buff[256];
char recv_buff[256];
char *token = NULL;
char *delim = " ";
while (1) {
printf("ftp > ");
fgets(buff, sizeof(buff), stdin);
buff[strlen(buff) - 1] = 0;
char *tmp = buff;
if (*tmp == 0) continue;
token = strtok(tmp, delim);
#if 1
if (COMPARE(token, ==, "ls")) {
char *send_data = packet("ls", 0, NULL);
send(sockfd, send_data, HEAD_SIZE, 0);
free(send_data);
while (1) {
recvlen = recv(sockfd, recv_buff, 4, 0);
if (recvlen <= 0) break;
int size = *(int *)recv_buff;
memset(recv_buff, 0, 0);
recv(sockfd, recv_buff, size, 0);
if (COMPARE(recv_buff, ==, "ok")) break;
printf("%s ", recv_buff);
fflush(stdout);
}
printf("\n");
} else if (COMPARE(token, ==, "get")) {
char *data = strtok(NULL, delim);
char *send_data = packet("get", strlen(data) + 1, data);
send(sockfd, send_data, HEAD_SIZE+strlen(data)+1, 0);
free(send_data);
recvlen = recv(sockfd, recv_buff, 4, 0);
if (recvlen <= 0) break;
int size = *(int *)recv_buff;
memset(recv_buff, 0, 0);
recvlen = recv(sockfd, recv_buff, size, 0);
FILE *fp = fopen(data, "wb");
size_t len = fwrite(recv_buff, 1, recvlen, fp);
printf("file download\n");
fclose(fp);
} else if (COMPARE(token, ==, "put")) {
char *data = strtok(NULL, delim);
FILE *fp = fopen(data, "rb");
if (fp == NULL) {
printf("file open failed\n");
continue;
}
size_t readlen = fread(send_buff, 1, sizeof(send_buff), fp);
char *tmp = packet("put", readlen, send_buff);
send(sockfd, tmp, HEAD_SIZE+readlen, 0);
free(tmp);
fclose(fp);
memset(recv_buff, 0, 0);
recv(sockfd, recv_buff, 3, 0);
if (COMPARE(recv_buff, ==, "ok"))
printf("put file finish\n");
} else if (COMPARE(token, ==, "quit")) {
close(sockfd);
return 0;
}
#endif
}
close(sockfd);
return 0;
}
char *packet(const char *cmd, int size, const char *data) {
char *ret = malloc(sizeof(char *) + sizeof(int) + size);
memcpy(ret, cmd, 4);
*(int *)(ret + 4) = size;
if (size != 0)
memcpy(ret + HEAD_SIZE, data, size);
return ret;
}
显示结果:
一个简单的ftp软件就实现了,不过有太多的缺陷和问题,等以后修改了再更新