udp的69端口用于初次访问
后续的通讯时新的端口,容易搞错
初次访问ftp后,根据recvfrom的参数返回值找到真正通讯的端口
#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<unistd.h>
#include<string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define IP "192.168.1.4"
#define PORT 69
#define SIZE 516
#define MSG_ERR(msg) do{\
fprintf(stderr,"%d",__LINE__);\
perror(msg);\
return -1;\
}while(0)
void showmenu();//菜单打印
void getfirst(char *ch);//获取输入的第一个字符
void download(int fd,struct sockaddr_in sever,ssize_t len);//下载
void upload(int fd,struct sockaddr_in sever);//上传
int main(int argc,const char *argv[])
{
//1:创建ipv4 udp socket
int fd = socket(AF_INET,SOCK_DGRAM,0);
if(-1 == fd)
MSG_ERR("socket");
//封装服务器信息
struct sockaddr_in sever;
sever.sin_family = AF_INET;
sever.sin_addr.s_addr = inet_addr(IP);
sever.sin_port = htons(PORT);
//用户界面展示
char ch;
showmenu();
getfirst(&ch);
switch(ch)
{
case '1': download(fd,sever,sizeof(sever));break;//1:下载
case '2': upload(fd,sever);break;//2:上传
case '3': exit(0);break;//退出
default : printf("\tOh,错误的信号\n");getfirst(&ch);break;
}
/*4:接收
struct sockaddr_in recv;
socklen_t len = sizeof(recv);
char recvbuff[SIZE] = "";
recvfrom(fd,recvbuff,sizeof(recvbuff),0,(struct sockaddr*)&recv,&len);
printf("%s\n",recvbuff);
5:关闭
*/
close(fd);
return 0;
}
void showmenu()
{
printf("\t*******************************\n");
printf("\t********** 1: 下载 ************\n");
printf("\t********** 2: 上传 ************\n");
printf("\t********** 3: 退出 ************\n");
printf("\t*******************************\n");
}
void getfirst(char *ch)
{
printf("\t请选择>> ");
*ch = getchar();
while(getchar() != '\n');
}
void download(int fd,struct sockaddr_in sever,ssize_t len)
{
char buff[SIZE] = "";
buff[1] = 1;
printf("\t请输入文件名>> ");
scanf("%s",buff+2);
ssize_t filelen = strlen(buff+2);//获取文件名所占的字节数
strcpy(buff+2+filelen+1,"octet");
//打开文件
int copyfd = open(buff+2,O_WRONLY|O_CREAT,0664);
//发送下载请求
sendto(fd,buff,filelen+2+1+5+1,0,(struct sockaddr *)&sever,len);
//printf("\n%d\n\n",ntohs(sever.sin_port));
//打印ftp服务器端口,验证后续给客户端传输数据的是另一个端口
//接受服务器返回的信息
struct sockaddr_in re;
socklen_t relen = sizeof(re);
unsigned int block = 0;
int reslen = 0;
while(1)
{
reslen = recvfrom(fd,buff,sizeof(buff),0,(struct sockaddr *)&re,&relen);
// printf("\n%d\n\n",ntohs(re.sin_port));
// 在此处打印客户端从哪个端口收到的数据,与69不同,证明服务器开辟另一个端口用于发送数据
if(buff[1] == 3)
{
if(block+1 == ntohs(*(unsigned short*)(buff+2)))
{
printf("%d\n",ntohs(*(unsigned short*)(buff+2)));
write(copyfd,buff+4,reslen-4);
block++;
//printf("%#x\n",*(unsigned short*)buff);
if(reslen < 512)
{
printf("%ld\n",strlen(buff+4));
printf("reslen = %d\n",reslen);
printf("\n%d下载完成\n",__LINE__);
buff[1] = 4;
bzero(buff+4,sizeof(buff)-4);
sendto(fd,buff,4,0,(struct sockaddr*)&re,relen);
break;
}
buff[1] = 4;
bzero(buff+4,sizeof(buff)-4);
sendto(fd,buff,4,0,(struct sockaddr*)&re,relen);
}
else
{
printf("传输块错误\n");
break;
}
}
else if(buff[1] == 5)
{
printf("err\n");
break;
}
}
}
void upload(int fd,struct sockaddr_in se)
{
struct sockaddr_in sever = se;
//1:发送上传请求
char buff[SIZE] = "";
char file[128] = "";
printf("\t请输入要上传的文件>>> ");
scanf("%s",file);
while(getchar() != '\n');
sprintf(buff,"%c%c%s%c%s%c",0,2,file,0,"octet",0);
sendto(fd,buff,9+strlen(file),0,(struct sockaddr*)&sever,sizeof(sever));
//2:打开要上传的文件
int filefd = open(file,O_RDONLY);
if(filefd < 0)
printf("请检查文件名或权限是否不足\n");
int ret;
//3:获取发送ACK的端口号
struct sockaddr_in recv;
socklen_t len = sizeof(recv);
recvfrom(fd,buff,sizeof(buff),0,(struct sockaddr*)&recv,&len);
printf("回信表头 :%#06x\n",*(unsigned short *)buff);
printf("回信数据段:%#06x\n",*(unsigned short *)(buff+2));
while(1)
{
//4:封装上传数据
buff[1] = 3;
buff[3] = buff[3]+1;
ret = read(filefd,buff+4,sizeof(buff)-4);
if(ret == -1)
{
perror("read");
return ;
}
//5:开始上传
// sendto(fd,buff,ret,0,(struct sockaddrte*)&recv,sizeof(recv));
sendto(fd,buff,ret+4,0,(struct sockaddr *)&recv,sizeof(recv));
//printf("发送内容 :%s\n",buff+4);
bzero(buff+4,sizeof(buff)-4);
if(ret < (sizeof(buff)-4))
{
printf("%d",ret);
printf("上传完成\n");
break;
}
recvfrom(fd,buff,sizeof(buff),0,(struct sockaddr*)&recv,&len);
}
return ;
}