小项目,搭建服务器,下载文件
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <arpa/inet.h>
#define MSG_ERR(msg)do{\
fprintf(stderr,"line:%d",__LINE__);\
perror(msg);\
return -1;\
}while(0)
#define PORT 69//端口号
#define IP "192.168.8.130"
int main(int argc, const char *argv[])
{
//创建套接字
int sfd = socket(AF_INET,SOCK_DGRAM,0);
if(sfd<0)
MSG_ERR("socket");
//服务器的IP和端口
struct sockaddr_in sin;
sin.sin_family=AF_INET;//IPV4
sin.sin_port=htons(PORT);//端口
sin.sin_addr.s_addr=inet_addr(IP);//IP
char readbuf[128]="";
unsigned short* pa=(unsigned short*)&readbuf;
*pa=htons(1);//操作码:1
char *pb=readbuf+2;
strcpy(pb,argv[1]);//文件名:argv[1]
char *pc=pb+strlen(pb);//偏移位置
*pc=0;//0
char *pd=pc+1;
strcpy(pd,"octet");//模式
int size;
size=2+strlen(pb)+1+strlen(pd)+1;//大小
//向服务器发送读写请求
if(sendto(sfd,readbuf,size,0,(struct sockaddr*)&sin,sizeof(sin))<0)
MSG_ERR("sendto");
short ACKbuf[2];//ACK
unsigned short *p1=ACKbuf;//操作码
*p1=htons(4);
short b=1;//块编号
unsigned short *p=ACKbuf+1;
char databuf[600];//数据包存放
int size2=sizeof(sin);//服务器信息结构体大小
ssize_t res=0;
ssize_t res2=0;
char buf[128]="";
//在当前目录下创建文件
strcat(buf,"./");
//命令行读取参数
strcat(buf,argv[1]);
//以读写,追加方式创建要拷贝的文件名
int fd=open(buf,O_RDWR|O_APPEND|O_CREAT|O_TRUNC,0666);
if(fd<0)
MSG_ERR("open");
while(1)
{
//字符串清空
bzero(databuf,sizeof(databuf));
//读取服务器传过来的数据以及服务器的信息
res=recvfrom(sfd,databuf,sizeof(databuf),0,(struct sockaddr*)&sin,&size2);
//将读取的数据写入到创建的目录下,前四个字节是操作码和块编码,不需要写入
res2=write(fd,databuf+4,res-4);
if(res2<0)
MSG_ERR("write");
if(res<0)
MSG_ERR("recvfrom");
if(res2<512)//小于512代表文件读到末尾了
{
printf("数据读取完毕\n");
break;
}
//转成网络字节序
*p=htons(b);
//向服务器发送ACK;
if(sendto(sfd,ACKbuf,4,0,(struct sockaddr*)&sin,sizeof(sin))<0)
MSG_ERR("sendto");
b++;
}
close(sfd);
close(fd);
return 0;
}