cpp
复制代码
#include<myhead.h>
#define SER_IP "192.168.125.193" //服务器ip
#define SER_PORT 8888 //服务器端口号
#define CLI_IP "192.168.152.135" //客户端IP
#define CLI_PORT 8910 //客户端端口号
int main(int argc, const char *argv[])
{
//1、创建用于通信的套接字文件描述符
int cfd = socket(AF_INET, SOCK_STREAM, 0);
if(cfd == -1)
{
perror("socket error");
return -1;
}
printf("cfd = %d\n", cfd); //3
//2、绑定(非必须)
//2.1 填充地址信息结构体
struct sockaddr_in cin;
cin.sin_family = AF_INET;
cin.sin_port = htons(CLI_PORT);
cin.sin_addr.s_addr = inet_addr(CLI_IP);
//2.2 绑定
if(bind(cfd, (struct sockaddr*)&cin, sizeof(cin)) == -1)
{
perror("bind error");
return -1;
}
printf("bind success\n");
//3、连接服务器
//3.1填充要连接的服务器地址信息结构体
struct sockaddr_in sin;
sin.sin_family = AF_INET; //地址族
sin.sin_port = htons(SER_PORT); //端口号
sin.sin_addr.s_addr = inet_addr(SER_IP); //ip地址
//3.2 连接服务器
if(connect(cfd, (struct sockaddr*)&sin, sizeof(sin))==-1)
{
perror("connect error");
return -1;
}
printf("connect success\n");
//4、数据收发
char rbuf[5] = {0xff, 0x02, 0x00, 0x00, 0xff};
unsigned char bbuf[5] = {0xff, 0x02, 0x01, 0x00, 0xff};
//发送给服务器当做初始值
send(cfd, rbuf, sizeof(rbuf), 0);
sleep(1);
send(cfd, bbuf, sizeof(bbuf), 0);
char key = 0; //接收键盘输入的字符
while(1)
{
scanf("%c", &key); //键盘输入一个字符
getchar(); //吸收回车
switch(key)
{
case 'W':
case 'w':
{
rbuf[3] += 2; //每次操作的角度偏移2读
if(rbuf[3] >= 90)
{
rbuf[3] = 90;
}
send(cfd, rbuf, sizeof(rbuf), 0);
}
break;
case'S':
case's':
{
rbuf[3]-=2;
if(rbuf[3]<=-90)
{
rbuf[3]=-90;
}
send(cfd,rbuf,sizeof(rbuf),0);
}
break;
case'D':
case'd':
{
bbuf[3]+=2;
if(bbuf[3]>=180)
{
bbuf[3]=180;
}
send(cfd,bbuf,sizeof(bbuf),0);
}
break;
case'A':
case'a':
{
bbuf[3]-=2;
if(bbuf[3]<=0)
{
bbuf[3]=0;
}
send(cfd,bbuf,sizeof(bbuf),0);
}
break;
}
}
//5、关闭套接字
close(cfd);
return 0;
}
cpp
复制代码
#include<myhead.h>
#define SER_IP "192.168.125.64"
#define SER_POTR 69
int my_download(int cfd,struct sockaddr_in sin);
int my_upload(int cfd,struct sockaddr_in sin);
int my_save_data(char *p,int len);
int recv_ack(char *pack,int res);
int main(int argc, const char *argv[])
{
system("clear");
//创建通信套接字
int cfd=socket(AF_INET,SOCK_DGRAM,0);
if(cfd==-1)
{
perror("socket error");
return -1;
}
//定义地址结构体 保存客户端地址
struct sockaddr_in sin;
sin.sin_family=AF_INET;
sin.sin_port=htons(SER_POTR);
sin.sin_addr.s_addr=inet_addr(SER_IP);
int menu=0;
while(1)
{
puts("\t\t------请选择选项------");
printf("\t\t-------1.上传-------\n");
printf("\t\t-------2.下载-------\n");
printf("\t\t-------0.退出-------\n");
scanf("%d",&menu);
getchar();
switch(menu)
{
case 0:goto END;
case 1:
{
int res=my_upload(cfd,sin);
if(res==-1)
{
puts("my_upload error");
return -1;
}
}break;
case 2:
{
int res=my_download(cfd,sin);
if(res==-1)
{
puts("my_download error");
return -1;
}
}break;
default:
{
puts("输入有误,请重新输入");
}break;
}
}
END:
close(cfd);
return 0;
}
int my_download(int cfd,struct sockaddr_in sin)
{
//定义收发数据容器
char pack[516]="";
//组建请求协议包
//1.请求下载
printf("请输入要下载的文件名:");
char txt[32]="";
fgets(txt,sizeof(txt),stdin);
txt[strlen(txt)-1]=0;
short *p1=(short*)pack;
*p1=htons(1);//存入前两字节的操作码1代表读(下载)
char *p2=pack+2;
strcpy(p2,txt);//存入文件名及结尾的0
char *p3=p2+strlen(p2)+1;
strcpy(p3,"octet");//存入模式位及结尾的0
int packlen=4+strlen(p2)+strlen(p3);
//发送下载请求
if(sendto(cfd,pack,packlen,0,(struct sockaddr*)&sin,sizeof(sin))==-1)
{
perror("download request sendto error");
return -1;
}
while(1)
{
bzero(pack,sizeof(pack));
int sinlen=sizeof(sin);
int res=-1;
if((res=(recvfrom(cfd,pack,sizeof(pack),0,(struct sockaddr*)&sin,&sinlen)))==-1)
{
perror("my_download recvfrom error");
return -1;
}
int ack=recv_ack(pack,res);
if(ack==-1)
{
puts("my_download recv_ack error");
return -1;
}
*p1=htons(4);//设置ACK包
*(p1+1)=htons(ack);
//如果读取的长度小于516说明已经下载完成
if(res<sizeof(pack))
{
//最后一次回复ACK
sendto(cfd,pack,4,0,(struct sockaddr*)&sin,sizeof(sin));
printf("下载完成!\n");
break;//结束循环
}
//返回ACK包
if(sendto(cfd,pack,sizeof(pack),0,(struct sockaddr*)&sin,sizeof(sin))==-1)
{
perror("download ACK sendto error");
return -1;
}
}
return 0;
}
int my_upload(int cfd,struct sockaddr_in sin)
{
//定义收发数据容器
char pack[516]="";
//组建请求协议包
//1.请求写入
printf("请输入要上传的文件名:");
char txt[32]="";
fgets(txt,sizeof(txt),stdin);
txt[strlen(txt)-1]=0;
short *p1=(short*)pack;
*p1=htons(2);//存入前两字节的操作码2代表写(上传)
char *p2=pack+2;
strcpy(p2,txt);//存入文件名及结尾的0
char *p3=p2+strlen(p2)+1;
strcpy(p3,"octet");//存入模式位及结尾的0
int packlen=4+strlen(p2)+strlen(p3);
if(sendto(cfd,pack,packlen,0,(struct sockaddr*)&sin,sizeof(sin))==-1)
{
perror("upload request sendto error");
return -1;
}
//读取服务器的回复消息
bzero(pack,sizeof(pack));
int sinlen=sizeof(sin);
int res=-1;
if((res=(recvfrom(cfd,pack,sizeof(pack),0,(struct sockaddr*)&sin,&sinlen)))==-1)
{
perror("my_upload recvfrom error");
return -1;
}
int ack=recv_ack(pack,res);
if(ack==-1)
{
puts("recv_ack error");
return -1;
}
//2.开始上传数据
//2.1只读形式打开要上传的文件
int rfd=open(txt,O_RDONLY);
if(rfd==-1)
{
perror("upload open error");
return -1;
}
int i=1;
while(1)
{
bzero(pack,sizeof(pack));
//2.2设置发送数据的协议包
*p1=htons(3);//前两字节操作码为3时代表此为数据包
*(p1+1)=htons(i);//设置块编码从1开始
int rres=read(rfd,pack+4,512);//从文件中读取512数据存入数据域
packlen=4+rres;//本次的数据包大小
//发送数据
if(sendto(cfd,pack,packlen,0,(struct sockaddr*)&sin,sizeof(sin))==-1)
{
perror("upload data sandto error");
return -1;
}
if((res=(recvfrom(cfd,pack,sizeof(pack),0,(struct sockaddr*)&sin,&sinlen)))==-1)
{
perror("my_upload recvfrom error");
return -1;
}
ack=recv_ack(pack,res);//读取服务器的回复消息
if(ack==-1)
{
puts("recv_ack error");
return -1;
}else if(ack<i)//服务器返回的块编码小于当前发送的
{
//光标返回发送之前的位置重新发送
lseek(rfd,-res,SEEK_CUR);
}else if(ack==i)//服务器已接收该数据包可以发送下一个
{
i++;//块编码+1
}
if(rres<512)//发送完成
{
printf("上传完成!\n");
break;
}
}
close(rfd);
return 0;
}
int my_save_data(char *p,int len)
{
//追加写的形式创建一个文件存储下载的数据
int wfd=open("./downtxt",O_WRONLY|O_APPEND|O_CREAT,0664);
if(wfd==-1)
{
perror("my_download open error");
return -1;
}
write(wfd,p,len);
close(wfd);
return 0;
}
int recv_ack(char *pack,int res)
{
short *p=(short*)pack;
short num=ntohs(*p);//获取发来消息的操作码
switch(num)
{
case 3:
{
//保存数据
int seve=my_save_data(pack+4,res-4);
if(seve==-1)
{
puts("my_save_data error");
return -1;
}
}break;
case 4:
break;
case 5:
{
//收到错误码 输出差错码和差错信息
printf("ERROR:%d:%s\n",ntohs(*(p+1)),pack+4);
return -1;
}break;
}
return ntohs(*(p+1));//返回块编码
}