使用 C 中的套接字将文件发送到 ftp 服务器
Send file to ftp server using sockets in C
我正在尝试使用套接字将文件上传到我的 ftp 服务器。它连接到服务器并可以读取目录但不上传文件。 "STOR" 命令在服务器中创建一个内容为空的文件。为什么我从服务器收到 "No data connection" 响应而我的文件是空的?
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
int main(int argc, char *argv[])
{
argv[0]="2";
argv[1]="ip";
int sockfd = 0, n = 0;
char recvBuff[1024];
struct sockaddr_in serv_addr;
char mesUser[100]="USER ftpuser\n";
char mesPass[100]="PASS pass\n";
char meStor[100]="STOR xx\n";
char mesPasv[100]="PASV\n";
char meAppe[100]="APPE xx\n";
argc=2;
if(argc != 2)
{
printf("\n Usage: %s <ip of server> \n",argv[0]);
return 1;
}
memset(recvBuff, '0',sizeof(recvBuff));
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("\n Error : Could not create socket \n");
return 1;
}
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(21);
if(inet_pton(AF_INET, argv[1], &serv_addr.sin_addr)<=0)
{
printf("\n inet_pton error occured\n");
return 1;
}
//serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
printf("\n Error : Connect Failed \n");
return 1;
}
if( send(sockfd , mesUser , strlen(mesUser) , 0) < 0)
{
perror("send failed");
return 1;
}
if( send(sockfd , mesPass , strlen(mesPass) , 0) < 0)
{
perror("send failed");
return 1;
}
char* fr_name = "pic.jpg";
FILE *fr = fopen(fr_name, "r");
if(fr == NULL){
printf("File cannot be opened");
return 0;
}
else{
/*if( send(sockfd , mesPasv , strlen(mesPasv) , 0) < 0)
{
perror("send failed");
return 1;
}*/
if( send(sockfd , meStor , strlen(meStor) , 0) < 0)
{
perror("send failed");
return 1;
}
char buffer[100];
fscanf(fr,"%s",buffer);
write(sockfd,buffer,100);
if( send(sockfd , meAppe , strlen(meAppe) , 0) < 0)
{
perror("send failed");
return 1;
}
//close(sockfd);
}
/*if( send(sockfd , meStor , strlen(meStor) , 0) < 0)
{
perror("send failed");
return 1;
}
*/
while ( (n = read(sockfd, recvBuff, sizeof(recvBuff)-1)) > 0)
{
recvBuff[n] = 0;
if(fputs(recvBuff, stdout) == EOF)
{
printf("\n Error : Fputs error\n");
return 0;
}
}
if(n < 0)
{
printf("\n Read error \n");
return 0;
}
return 0;
}
输出:
220---------- Welcome to Pure-FTPd [privsep] [TLS] ----------
220-You are user number 6 of 50 allowed.
220-Local time is now 14:41. Server port: 21.
220 You will be disconnected after 15 minutes of inactivity.
331 User username OK. Password required
230 OK. Current restricted directory is /
425 No data connection
425 No data connection
看来您对FTP协议的理解还不全面。 FTP 致力于在客户端和服务器之间建立 2 个套接字连接的想法。第一个是 "control" 连接,第二个是 "data" 连接。在控制连接上,文本命令来回发送,就像您在代码中所做的那样。当需要来回发送数据时,使用数据连接完成。
FTP有两种方式建立数据连接,described here:
- 活动:客户端指定一个端口到服务器,服务器连接到客户端机器上的那个端口。这很糟糕,因为防火墙和 NAT 的设计正是为了避免这类连接。
- 被动:服务器给客户端一个连接端口,客户端连接到服务器机器上的那个端口。
简而言之,您需要:
- 使用
PASV
命令。
- 解析服务器的响应以获取端口号(可能使用
scanf
)。
- 打开到服务器上该端口的数据连接。
- 通过该数据连接放置您的文件。
自从我上次用 C 编写套接字以来已经有一段时间了,我没有时间编写示例,但这应该足以让您入门。 (Here 是 FTP 的规范。像这样的 RFC 读起来很费力,但它们是明确的,可以回答很多问题,如果你能学会阅读它们的话。)
我希望这对你有用:
int receiveFile(int socket, char text[]) {
FILE *fp;
int nsize,k, i, size=0, temp_size, mul = 1, numbytes, lala, recvd;
int count_freq, repeat;
char ch,buf[20],file_buf[505], temp_buf[505];
saferead(socket, text,80);
if(text[0] == '/')
return 1;
nsize = strlen(text);
char name[nsize];
strncpy(name, text, nsize-1);
name[nsize-1] = '[=10=]';
if ((fp = fopen(name,"w")) == NULL) {
perror(" Can't open file");
return 1;
}
if ((numbytes=recv(socket, buf, 10, 0)) == -1) {
perror("Cant receive size of the file....\n\n");
return 1;
}
for( i=0; i<=9; i++ ){
size = size + ( buf[i]*mul );
mul = mul * 10;
}
recvd = 0;
printf("Received File: %s\n", name);
repeat = size/MAXDATASIZE;
if ( repeat>50 )
count_freq = repeat/50;
i=0;
while( recvd < size ){
if ((numbytes=recv(socket, temp_buf, MAXDATASIZE, 0)) == -1) {
perror("Error receiving file from server....\n\n");
return 1;
}
fwrite( temp_buf, sizeof(temp_buf[0]), numbytes, fp );
recvd = recvd + numbytes;
}
fclose(fp);
}
int sendFile(int socket, char text[]) {
FILE *fp;
int size =0, k, status, nsize = 0, temp_size, i, sent, numbytes, lala;
char buf[20], file_buf[505], temp_buf[505];
char ch;
struct stat info;
nsize = strlen(text);
char name[nsize];
lala = strlen(name);
strncpy(name, text, nsize-1);
name[nsize-1] = '[=11=]';
lala = strlen(name);
if((fp = fopen(name, "r")) == NULL) {
perror("Can't open file");
text[0] = '/';
write(socket,text, 80);
return 1;
}
write(socket,text, 80);
printf("Sending File: %s\n",text);
status = stat( name,&info );
if( status == -1 ){
printf(" fstat failed \n");
return 1;
}
size = info.st_size;
temp_size = size;
for( i=0; i<=9; i++ ) {
buf[i] = size%10;
size = size/10;
}
if (send(socket, buf, 10, 0) == -1){
perror("Cant send file size...\n\n");
return 1;
}
i = 0;
sent = 0;
while( sent <= temp_size ){
ch = fgetc(fp);
if( sent == temp_size ){
if (i>0){
if (( numbytes = send(socket, file_buf, i, 0)) == -1)
perror("Error in sending file.....\n\n\n");
}
break;
}
file_buf[i++] = ch;
if(i == MAX_BUFSIZE){
if (( numbytes = send(socket, file_buf, MAX_BUFSIZE, 0)) == -1)
perror("Error in sending file....\n\n\n");
i = 0;
}
sent++;
}
fclose(fp);
}
我正在尝试使用套接字将文件上传到我的 ftp 服务器。它连接到服务器并可以读取目录但不上传文件。 "STOR" 命令在服务器中创建一个内容为空的文件。为什么我从服务器收到 "No data connection" 响应而我的文件是空的?
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
int main(int argc, char *argv[])
{
argv[0]="2";
argv[1]="ip";
int sockfd = 0, n = 0;
char recvBuff[1024];
struct sockaddr_in serv_addr;
char mesUser[100]="USER ftpuser\n";
char mesPass[100]="PASS pass\n";
char meStor[100]="STOR xx\n";
char mesPasv[100]="PASV\n";
char meAppe[100]="APPE xx\n";
argc=2;
if(argc != 2)
{
printf("\n Usage: %s <ip of server> \n",argv[0]);
return 1;
}
memset(recvBuff, '0',sizeof(recvBuff));
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("\n Error : Could not create socket \n");
return 1;
}
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(21);
if(inet_pton(AF_INET, argv[1], &serv_addr.sin_addr)<=0)
{
printf("\n inet_pton error occured\n");
return 1;
}
//serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
printf("\n Error : Connect Failed \n");
return 1;
}
if( send(sockfd , mesUser , strlen(mesUser) , 0) < 0)
{
perror("send failed");
return 1;
}
if( send(sockfd , mesPass , strlen(mesPass) , 0) < 0)
{
perror("send failed");
return 1;
}
char* fr_name = "pic.jpg";
FILE *fr = fopen(fr_name, "r");
if(fr == NULL){
printf("File cannot be opened");
return 0;
}
else{
/*if( send(sockfd , mesPasv , strlen(mesPasv) , 0) < 0)
{
perror("send failed");
return 1;
}*/
if( send(sockfd , meStor , strlen(meStor) , 0) < 0)
{
perror("send failed");
return 1;
}
char buffer[100];
fscanf(fr,"%s",buffer);
write(sockfd,buffer,100);
if( send(sockfd , meAppe , strlen(meAppe) , 0) < 0)
{
perror("send failed");
return 1;
}
//close(sockfd);
}
/*if( send(sockfd , meStor , strlen(meStor) , 0) < 0)
{
perror("send failed");
return 1;
}
*/
while ( (n = read(sockfd, recvBuff, sizeof(recvBuff)-1)) > 0)
{
recvBuff[n] = 0;
if(fputs(recvBuff, stdout) == EOF)
{
printf("\n Error : Fputs error\n");
return 0;
}
}
if(n < 0)
{
printf("\n Read error \n");
return 0;
}
return 0;
}
输出:
220---------- Welcome to Pure-FTPd [privsep] [TLS] ----------
220-You are user number 6 of 50 allowed.
220-Local time is now 14:41. Server port: 21.
220 You will be disconnected after 15 minutes of inactivity.
331 User username OK. Password required
230 OK. Current restricted directory is /
425 No data connection
425 No data connection
看来您对FTP协议的理解还不全面。 FTP 致力于在客户端和服务器之间建立 2 个套接字连接的想法。第一个是 "control" 连接,第二个是 "data" 连接。在控制连接上,文本命令来回发送,就像您在代码中所做的那样。当需要来回发送数据时,使用数据连接完成。
FTP有两种方式建立数据连接,described here:
- 活动:客户端指定一个端口到服务器,服务器连接到客户端机器上的那个端口。这很糟糕,因为防火墙和 NAT 的设计正是为了避免这类连接。
- 被动:服务器给客户端一个连接端口,客户端连接到服务器机器上的那个端口。
简而言之,您需要:
- 使用
PASV
命令。 - 解析服务器的响应以获取端口号(可能使用
scanf
)。 - 打开到服务器上该端口的数据连接。
- 通过该数据连接放置您的文件。
自从我上次用 C 编写套接字以来已经有一段时间了,我没有时间编写示例,但这应该足以让您入门。 (Here 是 FTP 的规范。像这样的 RFC 读起来很费力,但它们是明确的,可以回答很多问题,如果你能学会阅读它们的话。)
我希望这对你有用:
int receiveFile(int socket, char text[]) {
FILE *fp;
int nsize,k, i, size=0, temp_size, mul = 1, numbytes, lala, recvd;
int count_freq, repeat;
char ch,buf[20],file_buf[505], temp_buf[505];
saferead(socket, text,80);
if(text[0] == '/')
return 1;
nsize = strlen(text);
char name[nsize];
strncpy(name, text, nsize-1);
name[nsize-1] = '[=10=]';
if ((fp = fopen(name,"w")) == NULL) {
perror(" Can't open file");
return 1;
}
if ((numbytes=recv(socket, buf, 10, 0)) == -1) {
perror("Cant receive size of the file....\n\n");
return 1;
}
for( i=0; i<=9; i++ ){
size = size + ( buf[i]*mul );
mul = mul * 10;
}
recvd = 0;
printf("Received File: %s\n", name);
repeat = size/MAXDATASIZE;
if ( repeat>50 )
count_freq = repeat/50;
i=0;
while( recvd < size ){
if ((numbytes=recv(socket, temp_buf, MAXDATASIZE, 0)) == -1) {
perror("Error receiving file from server....\n\n");
return 1;
}
fwrite( temp_buf, sizeof(temp_buf[0]), numbytes, fp );
recvd = recvd + numbytes;
}
fclose(fp);
}
int sendFile(int socket, char text[]) {
FILE *fp;
int size =0, k, status, nsize = 0, temp_size, i, sent, numbytes, lala;
char buf[20], file_buf[505], temp_buf[505];
char ch;
struct stat info;
nsize = strlen(text);
char name[nsize];
lala = strlen(name);
strncpy(name, text, nsize-1);
name[nsize-1] = '[=11=]';
lala = strlen(name);
if((fp = fopen(name, "r")) == NULL) {
perror("Can't open file");
text[0] = '/';
write(socket,text, 80);
return 1;
}
write(socket,text, 80);
printf("Sending File: %s\n",text);
status = stat( name,&info );
if( status == -1 ){
printf(" fstat failed \n");
return 1;
}
size = info.st_size;
temp_size = size;
for( i=0; i<=9; i++ ) {
buf[i] = size%10;
size = size/10;
}
if (send(socket, buf, 10, 0) == -1){
perror("Cant send file size...\n\n");
return 1;
}
i = 0;
sent = 0;
while( sent <= temp_size ){
ch = fgetc(fp);
if( sent == temp_size ){
if (i>0){
if (( numbytes = send(socket, file_buf, i, 0)) == -1)
perror("Error in sending file.....\n\n\n");
}
break;
}
file_buf[i++] = ch;
if(i == MAX_BUFSIZE){
if (( numbytes = send(socket, file_buf, MAX_BUFSIZE, 0)) == -1)
perror("Error in sending file....\n\n\n");
i = 0;
}
sent++;
}
fclose(fp);
}