基于UDP的TFTP文件传输(客户端代码)
代码:
# include <my_head.h>
# define SERVER_PORT 69
# define SERVER_IP "192.168.125.91"
int do_download ( int client_fd, struct sockaddr_in server_in) ;
int do_updata ( int client_fd, struct sockaddr_in server_in) ;
int main ( int argc, const char * argv[ ] )
{
int client_fd = socket ( AF_INET, SOCK_DGRAM, 0 ) ;
if ( client_fd < 0 )
{
ERR_MSG ( "socket" ) ;
return - 1 ;
}
printf ( "套接字创建成功 client_fd = %d\n" , client_fd) ;
int reuse = 1 ;
if ( setsockopt ( client_fd, SOL_SOCKET, SO_REUSEADDR, & reuse, sizeof ( reuse) ) < 0 )
{
ERR_MSG ( "setsockopt" ) ;
return - 1 ;
}
printf ( "允许端口快速复用成功\n" ) ;
struct sockaddr_in server_addr;
server_addr. sin_family = AF_INET;
server_addr. sin_port = htons ( SERVER_PORT) ;
server_addr. sin_addr. s_addr = inet_addr ( SERVER_IP) ;
char choose = 0 ;
while ( 1 )
{
printf ( "-------------------菜单--------------------\n" ) ;
printf ( "-----------------1. 下载-------------------\n" ) ;
printf ( "-----------------2. 上传-------------------\n" ) ;
printf ( "-----------------3. 退出-------------------\n" ) ;
printf ( "-------------------------------------------\n" ) ;
printf ( "请输入 : " ) ;
choose = getchar ( ) ;
while ( getchar ( ) != '\n' )
;
switch ( choose)
{
case '1' :
do_download ( client_fd, server_addr) ;
break ;
case '2' :
do_updata ( client_fd, server_addr) ;
break ;
case '3' :
goto END;
break ;
default :
printf ( "选择错误,请重新输入\n" ) ;
break ;
}
}
END:
close ( client_fd) ;
return 0 ;
}
int do_download ( int client_fd, struct sockaddr_in server_in)
{
unsigned short ACK[ 2 ] = { 0 } ;
char name[ 32 ] ;
printf ( "请输入想要下载的文件名 : " ) ;
scanf ( "%s" , name) ;
while ( getchar ( ) != 10 )
;
char buff[ 516 ] ;
unsigned short * opcode = ( unsigned short * ) buff;
* opcode = htons ( 1 ) ;
char * p2 = ( char * ) ( opcode + 1 ) ;
strcpy ( p2, name) ;
char * mode = p2 + strlen ( p2) + 1 ;
strcpy ( mode, "octet" ) ;
size_t size = 2 + strlen ( p2) + 1 + strlen ( mode) + 1 ;
if ( sendto ( client_fd, buff, size, 0 , ( struct sockaddr * ) & server_in, sizeof ( server_in) ) < 0 )
{
ERR_MSG ( "sendto" ) ;
return - 1 ;
}
printf ( "下载协议发送成功\n" ) ;
ssize_t res = 0 ;
socklen_t server_in_len = sizeof ( server_in) ;
umask ( 0 ) ;
int fd_w = open ( name, O_WRONLY | O_CREAT | O_TRUNC, 0664 ) ;
while ( 1 )
{
res = recvfrom ( client_fd, buff, sizeof ( buff) , 0 , ( struct sockaddr * ) & server_in, & server_in_len) ;
if ( res < 0 )
{
ERR_MSG ( "recvfrom" ) ;
return - 1 ;
}
char * data = buff + 4 ;
if ( write ( fd_w, data, res - 4 ) < 0 )
{
ERR_MSG ( "write" ) ;
return - 1 ;
}
ACK[ 0 ] = htons ( 4 ) ;
ACK[ 1 ] = * ( ( ( unsigned short * ) buff) + 1 ) ;
if ( sendto ( client_fd, ACK, sizeof ( ACK) , 0 , ( struct sockaddr * ) & server_in, sizeof ( server_in) ) < 0 )
{
ERR_MSG ( "sendto" ) ;
return - 1 ;
}
if ( ( res - 4 ) < 512 )
{
printf ( "下载结束\n" ) ;
break ;
}
}
close ( fd_w) ;
return 0 ;
}
int do_updata ( int client_fd, struct sockaddr_in server_in)
{
struct sockaddr_in new_in;
socklen_t new_in_len = sizeof ( new_in) ;
socklen_t server_in_len = sizeof ( server_in) ;
unsigned short block_num = 1 ;
char name[ 32 ] ;
printf ( "请输入想要上传的文件名 : " ) ;
scanf ( "%s" , name) ;
while ( getchar ( ) != 10 )
;
int fd_r = open ( name, O_RDONLY) ;
char buff[ 516 ] ;
unsigned short * opcode = ( unsigned short * ) buff;
* opcode = htons ( 2 ) ;
char * p2 = ( char * ) ( opcode + 1 ) ;
strcpy ( p2, name) ;
char * mode = p2 + strlen ( p2) + 1 ;
strcpy ( mode, "octet" ) ;
size_t size = 2 + strlen ( p2) + 1 + strlen ( mode) + 1 ;
if ( sendto ( client_fd, buff, size, 0 , ( struct sockaddr * ) & server_in, sizeof ( server_in) ) < 0 )
{
ERR_MSG ( "sendto" ) ;
return - 1 ;
}
printf ( "下载协议发送成功\n" ) ;
if ( recvfrom ( client_fd, buff, sizeof ( buff) , 0 , ( struct sockaddr * ) & new_in, & new_in_len) < 0 )
{
ERR_MSG ( "recvfrom" ) ;
return - 1 ;
}
printf ( "协议应答 操作码 : %u\n" , ntohs ( * ( ( unsigned short * ) buff) ) ) ;
printf ( "协议应答 块编号 : %u\n" , ntohs ( * ( ( unsigned short * ) buff + 1 ) ) ) ;
ssize_t res = - 1 ;
ssize_t recv_res = 0 ;
while ( 1 )
{
bzero ( buff, sizeof ( buff) ) ;
unsigned short * opcode = ( unsigned short * ) buff;
* opcode = htons ( 3 ) ;
unsigned short * b_num = opcode + 1 ;
* b_num = htons ( block_num) ;
res = read ( fd_r, buff + 4 , 512 ) ;
if ( res < 0 )
{
ERR_MSG ( "read" ) ;
return - 1 ;
}
else if ( 0 == res)
{
printf ( "读取文件完毕\n" ) ;
}
printf ( "sizeof(buff) = %ld\n" , sizeof ( buff) ) ;
server_in_len = sizeof ( server_in) ;
if ( sendto ( client_fd, buff, sizeof ( buff) , 0 , ( struct sockaddr * ) & new_in, new_in_len) < 0 )
{
ERR_MSG ( "sendto" ) ;
return - 1 ;
}
printf ( "发送数据包\n" ) ;
recv_res = recvfrom ( client_fd, buff, sizeof ( buff) , 0 , ( struct sockaddr * ) & new_in, & new_in_len) ;
if ( recv_res < 0 )
{
ERR_MSG ( "recvfrom" ) ;
return - 1 ;
}
printf ( "操作码--- : %u\n" , ntohs ( * ( ( unsigned short * ) buff) ) ) ;
printf ( "块编号--- : %u\n" , ntohs ( * ( ( unsigned short * ) buff + 1 ) ) ) ;
if ( 5 == ntohs ( * ( ( unsigned short * ) buff) ) )
{
printf ( "__%d__ ACK 操作码错误\n" , __LINE__ ) ;
printf ( "errro message : %s\n" , buff + 4 ) ;
return - 1 ;
}
if ( block_num - ( ntohs ( * ( ( unsigned short * ) buff + 1 ) ) ) )
{
printf ( "__%d__ 丢包\n" , __LINE__ ) ;
lseek ( fd_r, - ( block_num - ntohs ( * ( ( unsigned short * ) buff + 1 ) ) ) , SEEK_CUR ) ;
printf ( "向前偏移\n" ) ;
continue ;
}
if ( 0 == res)
{
printf ( "上传完毕\n" ) ;
break ;
}
block_num++ ;
printf ( "块编号------%u\n" , block_num) ;
}
close ( fd_r) ;
return 0 ;
}