#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#define RRQ 1
#define WRQ 2
#define DATA 3
#define ACK 4
#define ERROR 5
int main(int argc, char **argv){
//检测命令行3个参数
if (3 != argc)
{
printf("please use :%s <ip> <port>\n",argv[0]);
exit(-1);
}
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (-1 == sockfd)
perror("socket");
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET; // IPV4
server_addr.sin_port = htons(atoi(argv[2]));
server_addr.sin_addr.s_addr = inet_addr(argv[1]);
socklen_t server_addr_len = sizeof(server_addr);
//数据包--数据的长度以512Byte传输
unsigned char buffer[128] = {0};
char send_buffer[600]={0};
//返回的ACK
unsigned char ack[4];
unsigned short code = 0; //操作码
unsigned short num = 0; //块编号 或者 错误码
// char data[512]={0};
//校验收到的块编号
unsigned short send_block=1;
// int ret_block=0;
//文件指针
FILE*fp;
int recvfrom_len = 0;
int sendfrom_len = 0;
//输入文件名
char filename[32] = {0};
printf("上传文件名: ");
scanf("%s", filename);
size_t read_len;
//使用 sprintf 组包
//返回值:成功格式化字符的个数 0//-写- //文件名 //0 //二进制模式//0
sendfrom_len = sprintf((char *)buffer,"%c%c%s%c%s%c",0,WRQ, filename, 0, "octet", 0);
if (-1 == sendto(sockfd, buffer, sendfrom_len, 0, (struct sockaddr *)&server_addr, server_addr_len))
perror("sendto");
//接收--需要保存服务器的网络信息结构体 因为里面有临时端口
if (-1 == (recvfrom_len = recvfrom(sockfd,ack,4, 0, (struct sockaddr *)&server_addr, &server_addr_len)))
perror("recvfrom");
code= ntohs(*(unsigned short *)ack);// opcode
printf("code==%d ",code);//code此时为4
//num = ntohs(*(unsigned short *)(ack + 2));//
//printf("num==%d",num);//num此时为0
fp=fopen(filename,"rb");//打开文件
if(code==ACK){
while(1){
/*组装数据包*/
*((unsigned short*)send_buffer)=htons(DATA);
*((unsigned short*)(send_buffer+2))=htons(send_block);
read_len = fread(send_buffer+4,1,512,fp);
/*发送数据包*/
sendfrom_len = sendto(sockfd, send_buffer,read_len + 4,0,(struct sockaddr *)&server_addr, server_addr_len);
printf("sendfrom_len==%d ",sendfrom_len);
/*接收数据包*/
if((recvfrom_len = recvfrom(sockfd, ack,4, 0, (struct sockaddr *)&server_addr, &server_addr_len))<0){
perror("recvfrom");
return -1;
}
printf("recvfrom_len==%d ",sendfrom_len);
code = ntohs(*(unsigned short *)ack);//解析opcode
printf("code==%d ",code);//此时code等于4
num = ntohs(*(unsigned short *)(ack + 2));//解析块编号
printf("num==%d ",num);//此时num等于1
if( code == ACK && num==send_block ){
send_block++;//校验块编号+1
printf("send_block==%d\n",send_block);
}else{
return -1;
}
if( sendfrom_len < 516 ){
break;
}
}
}
else
{
printf("服务器无应答");
return -1;
}
printf("文件[%s]传成功\n", filename);
fclose(fp);
close(sockfd);
return 0;
}