机械臂和下载实现
机械臂操作实现
#include <myhead.h>
//宏定义阶段干什么
//传入服务器和客户端的IP和端口号
#define SER_IP "192.168.108.170" //服务器IP地址
#define SER_PORT 8888 //服务器端口号
#define CLI_IP "192.168.108.255" //客户端IP地址
#define CLI_PORT 7777 //客户端端口号
int main(int argc, const char *argv[])
{//1.创建用于通信的套接字文件描述符!!!!!!!!!!!!!!!!//判断创建是否成功!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//参数1:使用IPV4通信协议//参数2:使用TCP通信方式//参数3:参数2唯一指定int cfd=socket(AF_INET,SOCK_STREAM,0); if(cfd==-1){perror("socket error");return -1;}printf("测试:创建正常\n");//7.设置套接字端口号快速复用int res=1;struct linger reu={1};if(setsockopt(cfd,SOL_SOCKET,SO_REUSEADDR,&res,sizeof(res))==-1){perror("setsockopt error");return -1;}printf("测试:复用正常\n");//8.设置延迟关闭if(setsockopt(cfd,SOL_SOCKET,SO_LINGER,&reu,sizeof(reu))==-1){perror("setsockopt error");return -1;}printf("测试:延迟正常\n");//2.给客户端套接字绑定IP地址和端口号!!!!!!!!!!!!!!//2.1填充地址信息结构体//(1)通信域地址族//(2)服务器IP地址//(3)服务器端口号struct sockaddr_in cin;cin.sin_family=AF_INET; cin.sin_addr.s_addr=inet_addr(CLI_IP);cin.sin_port=htons(CLI_PORT);//2.2执行绑定工作!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//判断绑定是否成功!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//参数1:套接字文件描述符//参数2:通用地址信息结构体(将实际结构体地址类型强转)//参数3:参数2的大小if(bind(cfd,(struct sockaddr*)&cin,sizeof(cin))==-1){perror("bind error");return -1;}printf("测试:绑定正常\n");//3.连接服务器!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//3.1组装对端地址信息结构体!!!!!!!!!!!!!!!!!!!!!!!//(1)通信域地址族//(2)服务器IP地址//(3)服务器端口号struct sockaddr_in sin;sin.sin_family=AF_INET;sin.sin_addr.s_addr=inet_addr(SER_IP);sin.sin_port=htons(SER_PORT);//3.2链接操作if(connect(cfd,(struct sockaddr*)&sin,sizeof(sin))==-1){perror("connect error");return -1;}printf("测试:链接正常\n");//4.初始化机械臂位置//rbuf是红色机械臂//bbuf是蓝色机械臂char rbuf[5]={0xff,0x02,0x00,0x00,0xff};unsigned char bbuf[5]={0xff,0x02,0x01,0x5a,0xff};//4.1发送初始化信息给服务器send(cfd,rbuf,sizeof(rbuf),0);send(cfd,bbuf,sizeof(bbuf),0);printf("机械臂初始化成功!\n");//5.数据通信char buf[128]="";while(1){//5.1清空容器bzero(buf,sizeof(buf));//5.2从终端获取数据fgets(buf,sizeof(buf),stdin);buf[strlen(buf)-1]=0;//5.3判断输入按键if(strcmp(buf,"w")==0){rbuf[3]+=5;}else if(strcmp(buf,"s")==0){rbuf[3]-=5;}else if(strcmp(buf,"d")==0){bbuf[3]+=5;}else if(strcmp(buf,"a")==0){bbuf[3]-=5;}send(cfd,rbuf,sizeof(rbuf),0);send(cfd,bbuf,sizeof(bbuf),0);if(strcmp(buf,"quit")==0){break;}}//6.关闭套接字close(cfd);return 0;
}
实现下载功能
#include<myhead.h>#define SER_IP "192.168.108.170" //服务器IP
#define SER_PORT 69 //TFTP默认端口号
#define CLI_PORT 6666 //客户端端口号
#define BUF_SIZE 516 //TFTP数据包最大长度/******************主程序******************/
int main(int argc, const char *argv[])
{//1、创建一个用于通信的套接字文件描述符int cfd = socket(AF_INET, SOCK_DGRAM, 0);if(cfd == -1){perror("socket error");return -1;}//2、绑定客户端IP和端口号(TFTP需要固定端口以维持会话)struct sockaddr_in cin;cin.sin_family = AF_INET;cin.sin_addr.s_addr = htonl(INADDR_ANY); //使用本机可用IPcin.sin_port = htons(CLI_PORT);if(bind(cfd, (struct sockaddr*)&cin, sizeof(cin)) == -1){perror("bind error");close(cfd);return -1;}//3、设置服务器地址信息struct sockaddr_in sin;sin.sin_family = AF_INET;sin.sin_port = htons(SER_PORT);sin.sin_addr.s_addr = inet_addr(SER_IP);socklen_t ser_len = sizeof(sin);//4、向服务器发送下载请求char msgbuf[BUF_SIZE] = "";char filename[20] = "";printf("请输入要下载的文件名:");fgets(filename, sizeof(filename), stdin);filename[strcspn(filename, "\n")] = 0; //更安全的去除换行符//组装RRQ请求包short *op_code = (short *)msgbuf;*op_code = htons(1); //操作码:读请求char *p_filename = msgbuf + 2; //文件名起始位置strcpy(p_filename, filename);char *p_mode = p_filename + strlen(p_filename) + 1; //传输模式起始位置strcpy(p_mode, "octet"); //二进制传输模式//计算请求包长度:2字节操作码 + 文件名长度 + 1字节空分隔 + 模式长度 + 1字节空结尾int req_len = 2 + strlen(p_filename) + 1 + strlen(p_mode) + 1;//发送请求到服务器if(sendto(cfd, msgbuf, req_len, 0, (struct sockaddr*)&sin, ser_len) == -1){perror("sendto error");close(cfd);return -1;}//5、打开本地文件准备写入(使用用户输入的文件名)int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664);if(fd == -1){perror("open file error");close(cfd);return -1;}//6、文件传输循环int recv_len; //接收数据长度short block_num = 0; //期望接收的块编号struct sockaddr_in from_addr; //实际发送方地址socklen_t from_len = sizeof(from_addr);while(1){//接收服务器响应recv_len = recvfrom(cfd, msgbuf, BUF_SIZE, 0, (struct sockaddr*)&from_addr, &from_len);if(recv_len == -1){perror("recvfrom error");break;}//解析操作码short resp_op = ntohs(*(short*)msgbuf);//处理错误包if(resp_op == 5){short error_code = ntohs(*(short*)(msgbuf + 2));char *error_msg = msgbuf + 4;printf("下载失败!错误码:%d,原因:%s\n", error_code, error_msg);close(fd);unlink(filename); //删除空文件break;}//处理数据包if(resp_op == 3){//获取当前数据块编号short curr_block = ntohs(*(short*)(msgbuf + 2));//数据内容起始位置char *data = msgbuf + 4;//实际数据长度int data_len = recv_len - 4;//检查是否是期望的块编号if(curr_block == block_num + 1){//写入文件(只写实际接收到的数据长度)write(fd, data, data_len);block_num = curr_block; //更新已接收的块编号printf("已接收块 %d,数据长度:%d字节\n", block_num, data_len);//发送确认包(包含当前确认的块编号)*(short*)msgbuf = htons(4);*(short*)(msgbuf + 2) = htons(block_num);sendto(cfd, msgbuf, 4, 0, (struct sockaddr*)&from_addr, from_len);//判断是否为最后一块(数据长度小于512字节)if(data_len < 512){printf("文件下载完成!共接收 %d 个数据块\n", block_num);close(fd);break;}}else{//重复收到已处理的块,重新发送确认*(short*)msgbuf = htons(4);*(short*)(msgbuf + 2) = htons(block_num);sendto(cfd, msgbuf, 4, 0, (struct sockaddr*)&from_addr, from_len);}}}//7、关闭资源close(cfd);return 0;
}