cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
#define SER_PORT 69
#define PATHMAXLEN 128
char path[PATHMAXLEN];
enum mode_t{
READ = 1,
WRITE,
};
void menu(int cfd, struct sockaddr_in* psin, socklen_t addrlen);
void args_verify(int argc, const char *ip);
void net_init(int* pcfd, struct sockaddr_in* psin, const char* ip);
void download(int cfd, struct sockaddr_in* psin, socklen_t addrlen);
void upload(int cfd, struct sockaddr_in* psin, socklen_t addrlen);
void send_ack(int cfd, struct sockaddr_in* psin, socklen_t addrlen, unsigned short seq);
int main(int argc, const char *argv[])
{
args_verify(argc, argv[1]);
int cfd;
struct sockaddr_in sin;
socklen_t addrlen = sizeof(sin);
net_init(&cfd, &sin, argv[1]);
menu(cfd, &sin, addrlen);
close(cfd);
return 0;
}
void net_init(int* pcfd, struct sockaddr_in* psin, const char* ip){
*pcfd = socket(AF_INET, SOCK_DGRAM, 0);
if(-1 == *pcfd){
perror("socket");
exit(EXIT_FAILURE);
}
psin->sin_family = AF_INET;
psin->sin_port = htons(SER_PORT);
psin->sin_addr.s_addr = inet_addr(ip);
}
void menu(int cfd, struct sockaddr_in* psin, socklen_t addrlen){
while(1){
// system("clear");
puts("Welcome to tftp client");
puts("author: Jerry");
puts("Options:");
puts("① Download");
puts("② Upload");
puts("③ Quit");
printf(">> ");
char ch;
scanf("%c", &ch);
while(getchar() != '\n');
switch(ch){
case '1':
case 'd':
case 'D':
puts("Download:");
download(cfd, psin, addrlen);
getchar();
break;
case '2':
case 'u':
case 'U':
puts("Upload:");
upload(cfd, psin, addrlen);
getchar();
break;
case '3':
case 'q':
case 'Q':
puts("Bye!");
getchar();
return;
break;
default:
puts("Error: invalid option");
getchar();
break;
}
}
}
void args_verify(int argc, const char *ip){
if(argc < 2){
puts("Error: argument required");
goto ERR_ARG;
}
else if(argc > 2){
puts("Error: too many arguments");
goto ERR_ARG;
}
else{
char* ret = NULL;
int count = 0;
char ip_copy[64] = {};
strcpy(ip_copy, ip);
do{
if(ret)
ret = strtok(NULL, ".");
else
ret = strtok(ip_copy, ".");
count++;
if(!ret && count < 5 || count > 5)
goto ERR_IP;
else if(ret){
int part = atoi(ret);
if(part < 0 || part > 255)
goto ERR_IP;
}
}while(ret);
return;
}
ERR_IP:
puts("Error: invalid ip address");
ERR_ARG:
puts("Usage: tftp_cli <tftp_ser_ip>");
exit(EXIT_FAILURE);
}
void send_request(int cfd, struct sockaddr_in* psin, socklen_t addrlen, mode_t mode){
bzero(path, sizeof(path));
printf("Please enter the filename: ");
scanf("%s", path);
char request[137] = {};
unsigned short* p_short = (unsigned short*)request;
if(mode == READ)
*p_short = htons(1);
else if(mode == WRITE)
*p_short = htons(2);
char* p_char = request;
strcpy(p_char + 2 , path);
strcpy(p_char + 2 + strlen(path) + 1, "octet");
printf("cfd = %d, ip:%s, port:%hd\n", cfd, inet_ntoa(psin->sin_addr), ntohs(psin->sin_port));
sendto(cfd, request, 2 + strlen(path) + 2 + strlen("octet"), 0,
(struct sockaddr*)psin, addrlen);
}
void download(int cfd, struct sockaddr_in* psin, socklen_t addrlen){
send_request(cfd, psin, addrlen, READ);
unsigned short* p_short = NULL;
char data[516] = {};
struct sockaddr_in newsin;
socklen_t newaddrlen = sizeof(newsin);
unsigned int ret = recvfrom(cfd, data, sizeof(data), 0, (struct sockaddr*)&newsin, &newaddrlen);
p_short = (unsigned short*)data;
if(3 == ntohs(*p_short)){// data package
int fd_w = open(path, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR|S_IWUSR);
if(-1 == fd_w){
perror("open");
exit(EXIT_FAILURE);
}
while(ret == 516){
unsigned short seq = *(p_short + 1);
write(fd_w, data + 4, ret - 4);
send_ack(cfd, &newsin, newaddrlen, seq);
ret = recv(cfd, data, sizeof(data), 0);
seq = *(p_short + 1);
printf("ret=%u\n", ret);
if(ret < 516){
write(fd_w, data + 4, ret - 4);
break;
}
}
close(fd_w);
}
else if(5 == ntohs(*p_short)){// error package
unsigned short err_code = ntohs(*(p_short + 1));
char *err_str = (char *)(p_short + 2);
printf("Error %hu: %s\n", err_code, err_str);
}
return;
}
void upload(int cfd, struct sockaddr_in* psin, socklen_t addrlen){
send_request(cfd, psin, addrlen, WRITE);
unsigned short* p_short = NULL;
char ack[128] = {};
struct sockaddr_in newsin;
socklen_t newaddrlen = sizeof(newsin);
recvfrom(cfd, ack, sizeof(ack), 0, (struct sockaddr*)&newsin, &newaddrlen);
p_short = (unsigned short*)ack;
if(4 == ntohs(*p_short)){// ack package
unsigned short seq = USHRT_MAX, old_seq;
unsigned int ret;
char buf[516];
int fd_r = open(path, O_RDONLY);
if(-1 == fd_r){
perror("open");
exit(EXIT_FAILURE);
}
while(1){
old_seq = seq;
seq = ntohs(*(p_short + 1));
p_short = (unsigned short*)buf;
if(old_seq != seq){
if(ret < 512)
break;
bzero(buf, sizeof(buf));
*p_short = htons(3);
*(p_short + 1) = htons(seq + 1);
ret = read(fd_r, buf + 4, sizeof(buf) - 4);
}
sendto(cfd, buf, ret + 4, 0, (struct sockaddr*)&newsin, newaddrlen);
recv(cfd, ack, sizeof(ack), 0);
p_short = (unsigned short*)ack;
}
close(fd_r);
}
else if(5 == ntohs(*p_short)){// error package
unsigned short err_code = ntohs(*(p_short + 1));
char *err_str = (char *)(p_short + 2);
printf("Error %hu: %s\n", err_code, err_str);
}
return;
}
void send_ack(int cfd, struct sockaddr_in* psin, socklen_t addrlen, unsigned short seq){
char ack[4] = {};
unsigned short* p_short = (unsigned short*)ack;
*p_short = htons(4);
*(p_short + 1) = seq;
sendto(cfd, ack, sizeof(ack), 0, (struct sockaddr*)psin, addrlen);
}
下载文件:
上传文件:
1.项目中如何实现TCP的并发
2.TCP通信过程中的三次握手
3.四次挥手的过程
4.TCP/IP协议分几层?TCP/IP属于哪一层?
5.UDP为什么会丢包?
6.TCP是同步还是异步? 谈谈对同步异步的理解
7.什么是TCP的粘包现象,如何解决?
8.组播和广播的区别?
9.阻塞IO和非阻塞IO的区别?
10.并发与并行的区别?