网络编程 day3 c语言

该代码实现了一个简单的TFTP客户端,使用UDP协议进行文件下载。用户可以选择下载模式,输入文件名并接收服务器发送的数据包。接收到的数据包会被写入到用户指定的本地文件中。程序处理了数据包的接收、确认响应以及错误处理。
摘要由CSDN通过智能技术生成

写了一个tftp客户端的下载, udp协议

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>

#define ERR_MSG(msg) do{\
	perror(msg);\
	return -1;\
}while(0)

#define SUC_MSG(msg) do{\
	printf("%s success\n",msg);\
}while(0)

#define PORT 2305
#define IP "192.168.10.104"

#define SER_PORT 69
#define SER_IP "192.168.10.123"

int main(int argc, const char *argv[])
{
	
	int sfd = socket(AF_INET,SOCK_DGRAM,0);
	if(sfd < 0){
		ERR_MSG("socket");
	}
	SUC_MSG("socket");	
		
	//quick reuse of PORT
	int reuse = 1;
	if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse)) < 0){
		ERR_MSG("setsockopt");
	}

	struct sockaddr_in cin;
	cin.sin_family = AF_INET;
	cin.sin_port = htons(PORT);
	cin.sin_addr.s_addr = inet_addr(IP);
	if(bind(sfd,(struct sockaddr*)&cin,sizeof(cin)) < 0){
		ERR_MSG("bind");
	}	
	SUC_MSG("bind");

	//buf to restore all the packages
	char buf[516] = "";
	//a file name where you can read/write to
	char filename[32] = "";
	//a integer to restore how many bytes read/write during communication
	int res = 0;
	//a sockaddr_in to restore the temporary port
	struct sockaddr_in sin;
	int len = sizeof(sin);
	//the size of the request string
	int req_size = 0;
	//choice of download or upload
	int choice = 0;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(SER_PORT);
	sin.sin_addr.s_addr = inet_addr(SER_IP);

	//read request	
	bzero(buf,sizeof(buf));
	bzero(filename,sizeof(filename));
	while(1){	
		printf("enter 1 to download or 2 to upload:\n");
		scanf("%d",&choice);
		getchar();
		if(choice == 1 || choice == 2){
			break;
		}
	}
	//download
	if(choice == 1){
		*(short*)buf = htons(choice);
		printf("Please enter the file name you want to download:\n");
		fgets(filename,sizeof(filename),stdin);
		filename[strlen(filename) - 1] = 0;
		strcpy(buf + sizeof(short),filename);
		strcpy(buf + sizeof(short) + strlen(filename) + 1, "octet");
		req_size = sizeof(short) + strlen(filename) + 1 + strlen("octet") + 1;
		res = sendto(sfd,buf,req_size,0,(struct sockaddr*)&sin,sizeof(sin));	
		if(res < 0){
			ERR_MSG("request");
		}
		//if successfully requested for download,open a new file to save
		printf("Please enter a file name you want to save:\n");
		bzero(filename,sizeof(filename));
		fgets(filename,sizeof(filename),stdin);
		filename[strlen(filename) - 1] = 0;
		int fd = open(filename,O_CREAT|O_TRUNC|O_WRONLY,0664);
		if(fd < 0){
			ERR_MSG("open");
		}
		//package number
		int pac_num;
		//error number
		int err_num;
		while(1){	
			bzero(buf,sizeof(buf));
			res = recvfrom(sfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,&len);
			//if it's the last segment of the data
			if(res < 516){
				res = write(fd,buf + 2 * sizeof(short),res - 2*sizeof(short));
				printf("download finished\n");
				break;
			}else if(res < 0){
				ERR_MSG("recv");
			}
			//when no error happens,write in the data
			if(ntohs(*(short*)buf) == 3){
				pac_num = ntohs(*(short *)(buf + sizeof(short)));
				res = write(fd,buf + 2 * sizeof(short),sizeof(buf) - 2 *sizeof(short));
				bzero(buf,sizeof(buf));
				*(short*)buf = htons(4);
				*(short*)(buf + sizeof(short)) = htons(pac_num);
				//send back the ACK to the server
				res = sendto(sfd,buf,2*sizeof(short),0,(struct sockaddr*)&sin,len);
				if(res < 0){
					ERR_MSG("sendto");
				}
				//when error occurs,print out the error number and error message
			}else if(ntohs(*(short*)buf) == 5){
				err_num = ntohs(*(short *)(buf + sizeof(short)));
				printf("err number is %d, %s\n",err_num,buf + 2 * sizeof(short));
				break;
			}
			printf("[%s:%d] package%03d received\n",inet_ntoa(sin.sin_addr),ntohs(sin.sin_port),pac_num);
		}
		if(close(fd) < 0){
			ERR_MSG("close");
		}
	}
	//close all the file descriptors
	if((close(sfd))< 0){
		ERR_MSG("close");
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值