一、TCP机械臂测试
#include <myhead.h>#define SER_PORT 8888 // 与服务器保持一致
#define SER_IP "192.168.0.114" // 服务器ip地址int main(int argc, const char *argv[])
{// 创建文件描述符打开键盘文件int fd = open("/dev/input/event1", O_RDONLY);if (fd == -1){perror("open error");return -1;}// 定义结构体接收键盘文件的数据struct input_event ie;// 创建用于通信的套接字文件描述符int cfd = socket(AF_INET, SOCK_STREAM, 0);if (cfd == -1){perror("socket error");return -1;}printf("cfd = %d\n", cfd); // 连接到服务器// 填充服务器地址信息结构体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地址// 连接服务器if (connect(cfd, (struct sockaddr *)&sin, sizeof(sin)) == -1){perror("connect error");return -1;}printf("连接服务器成功\n");// 准备数据char rbuf[5] = {0xff, 0x02, 0x00, 0x10, 0xff};unsigned char bbuf[5] = {0xff, 0x02, 0x01, 0x10, 0xff};// 发送给服务器,以初始化机械臂send(cfd, rbuf, sizeof(rbuf), 0);sleep(1);send(cfd, bbuf, sizeof(bbuf), 0);printf("%#x\n", rbuf[3]);printf("%#x\n", bbuf[3]);while (1){// 接收键盘文件数据read(fd, &ie, sizeof(ie));switch (ie.code * ie.value){case 32: // d键rbuf[3] += 1;if (rbuf[3] > 90){rbuf[3] = 90;}send(cfd, rbuf, sizeof(rbuf), 0); // 传输数据给机械臂break;case 30: // a键rbuf[3] -= 1;if (rbuf[3] < -90){rbuf[3] = -90;}send(cfd, rbuf, sizeof(rbuf), 0); // 传输数据给机械臂break;case 31: // s键bbuf[3] -= 1;if (bbuf[3] <= 0){bbuf[3] = 0;}send(cfd, bbuf, sizeof(bbuf), 0); // 传输数据给机械臂break;case 17: // w键bbuf[3] += 1;if (bbuf[3] > 180){bbuf[3] = 180;}if (bbuf[3] < 0){bbuf[3] = 0;}send(cfd, bbuf, sizeof(bbuf), 0); // 传输数据给机械臂break;default:break;}/*if (buf == 'd') // 红机械臂右移一度{rbuf[3] = rbuf[3] + 1; // 修改角度printf("%#x\n", rbuf[3]);send(cfd, rbuf, sizeof(rbuf), 0); // 传输结果}if (buf == 'a') // 红机械臂左移一度{rbuf[3] = rbuf[3] - 1;printf("%#x\n", rbuf[3]);send(cfd, rbuf, sizeof(rbuf), 0);}if (buf == 's') // 蓝机械臂上移一度{bbuf[3] = bbuf[3] + 1;printf("%#x\n", bbuf[3]);send(cfd, bbuf, sizeof(bbuf), 0);}if (buf == 'w') // 蓝机械臂下移一度{bbuf[3] = bbuf[3] - 1;printf("%#x\n", bbuf[3]);send(cfd, bbuf, sizeof(bbuf), 0);}if (buf == 'q') // 直接设置{int val = 0;printf("红机械臂增减角度:");scanf("%d", &val); // 获取增减角度rbuf[3] = rbuf[3] + val; // 修改角度printf("%#x\n", rbuf[3]); // 传输结果getchar();printf("蓝机械臂增减角度:");scanf("%d", &val);bbuf[3] = bbuf[3] + val;printf("%#x\n", bbuf[3]);getchar();send(cfd, rbuf, sizeof(rbuf), 0);usleep(100);send(cfd, bbuf, sizeof(bbuf), 0);}buf = 0;*/}// 5、关闭套接字close(cfd);return 0;
}
二、基于UDP的TFTP文件传输
#include <myhead.h>
int main(int argc, char const *argv[])
{int sfd = socket(AF_INET, SOCK_DGRAM, 0);if (sfd == -1){perror("socket error");return -1;}// 下载请求包char buf[516] = "";short *p1 = (short *)buf; // 操作码*p1 = htons(1);char *p2 = buf + 2; // 文件名strcpy(p2, "5.png");char *p4 = p2 + strlen(p2) + 1; // 模式位strcpy(p4, "octet");int size = 2 + strlen(p2) + strlen(p4) + 2; // 请求包总长// 服务器地址信息struct sockaddr_in sin;sin.sin_family = AF_INET;sin.sin_port = htons(69);sin.sin_addr.s_addr = inet_addr("192.168.0.114");// 向服务器发送a下载请求sendto(sfd, buf, size, 0, (struct sockaddr *)&sin, sizeof(sin));int newfd = 0;if ((newfd = open("./5.png", O_WRONLY | O_CREAT | O_APPEND | O_TRUNC, 0664)) == -1){perror("open error");return -1;}while (1){socklen_t size_sin = sizeof(sin);bzero(buf, sizeof(buf)); // 清空bufint res = 0; // 接收服务器发送的数据if ((res = recvfrom(sfd, buf, sizeof(buf), 0, (struct sockaddr *)&sin, &size_sin)) == -1){perror("recvform error");return -1;}if (res <516){write(newfd, buf + 4, res - 4);*p1 = htons(4);sendto(sfd, buf, 4, 0, (struct sockaddr *)&sin, sizeof(sin));printf("下载结束\n");break;}write(newfd, buf + 4, res - 4); // 写入数据*p1 = htons(4); // 操作码置位 4sendto(sfd, buf, 4, 0, (struct sockaddr *)&sin, sizeof(sin)); // 发送ACK}close(sfd);close(newfd);return 0;
}
三、基于UDP的聊天室
1、服务器端
#include <myhead.h>
#define SER_PORT 6666 // 服务器端口号
#define SER_IP "192.168.179.128" // 服务器ip地址
// 定义结构体用于存储客服端的信息
struct MSG
{char type; // 信息类型 'L'表示登录 'T'表示群聊 'Q'表示退出 'S'表示系统消息char name[20];char msg[256];
};// 定义链表用于存储不同的客服端信息
struct ADDR
{struct sockaddr_in cin;struct ADDR *next;
};// 登录操作的函数
void do_login(int sfd, struct MSG buf, struct ADDR *addr, struct sockaddr_in cin)
{// 先遍历链表 将新用户加入群聊的消息发给所有人struct ADDR *tmp = addr; // 记录链表头节点while (tmp->next != NULL){tmp = tmp->next;if (-1 == sendto(sfd, &buf, sizeof(buf), 0, (struct sockaddr *)&(tmp->cin), sizeof(tmp->cin))){perror("sendto error");}}// 将新用户的网络信息结构体 头插入链表struct ADDR *pnew = NULL;if (NULL == (pnew = (struct ADDR *)malloc(sizeof(struct ADDR)))){printf("malloc error\n");return;}pnew->cin = cin;pnew->next = addr->next;addr->next = pnew;return;
}// 群聊操作的函数
void do_chat(int sfd, struct MSG buf, struct ADDR *addr, struct sockaddr_in cin)
{// 遍历链表,将群聊消息发给除了自己之外的所有人struct ADDR *ptmp = addr;while (ptmp->next != NULL){ptmp = ptmp->next;if (memcmp(&cin, &(ptmp->cin), sizeof(cin))){// 不是自己 就发送数据sendto(sfd, &buf, sizeof(buf), 0, (struct sockaddr *)&(ptmp->cin), sizeof(ptmp->cin));}}return;
}// 退出操作的函数
void do_quit(int sfd, struct MSG buf, struct ADDR *addr, struct sockaddr_in cin)
{// 遍历链表 是自己就将自己在链表中删除// 不是自己 就发送 退出群聊的数据struct ADDR *ptmp = addr;struct ADDR *del = NULL;while (ptmp->next != NULL){if (memcmp(&(ptmp->next->cin), &cin, sizeof(cin))){// 不是自己ptmp = ptmp->next;strcat(buf.name,"-系统接管");sendto(sfd, &buf, sizeof(buf), 0, (struct sockaddr *)&(ptmp->cin), sizeof(ptmp->cin));}else{// 是自己del = ptmp->next;ptmp->next = del->next;free(del);del = NULL;}}return;
}int main(int argc, char const *argv[])
{// 1、创建用于通信的套接字文件描述符int sfd = socket(AF_INET, SOCK_DGRAM, 0);if (sfd == -1){perror("scoket error");return -1;}printf("sfd = %d\n", sfd); // 3// 2、绑定ip地址和端口号// 2.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地址// 2.2、 绑定if (bind(sfd, (struct sockaddr *)&sin, sizeof(sin)) == -1){perror("bind error");return -1;}printf("bind success\n");// 3、数据接收struct MSG buf; // 定义用于信息接收的变量// 定义用于接收客服端网络信息的变量struct sockaddr_in cin; // 接收对端地址信息socklen_t addrlen = sizeof(cin); // 接收地址长度// 4、创建父子进程用于不同功能pid_t pid = 0;if (-1 == (pid = fork())){perror("fork error");return -1;}if (0 == pid) // 子进程,用于信息的处理{// 创建保存客户端信息的链表头节点struct ADDR *addr;if (NULL == (addr = (struct ADDR *)malloc(sizeof(struct ADDR)))){printf("malloc error\n");return -1;}memset(addr, 0, sizeof(addr));addr->next = NULL;while (1){ // 循环收发数据// 清空容器,确保信息准确memset(&buf, 0, sizeof(buf));memset(&cin, 0, sizeof(cin));// 接收客户端发送的消息,存放在msg中if (-1 == recvfrom(sfd, &buf, sizeof(buf), 0, (struct sockaddr *)&cin, &addrlen)){perror("recvfrom error");return -1;}switch (buf.type){ // 判断消息中的操作码,根据操作码执行对应操作case 'L': // 登录操作do_login(sfd, buf, addr, cin);break;case 'T': // 群聊操作do_chat(sfd, buf, addr, cin);break;case 'Q': // 退出操作do_quit(sfd, buf, addr, cin);break;}}}else // 父进程,用于发送系统信息{strcpy(buf.name, "系统消息");buf.type = 'T';while (1) // 循环在终端接收消息{memset(buf.msg, 0, sizeof(buf.msg));printf("输入信息:");fgets(buf.msg, 256, stdin);buf.msg[strlen(buf.msg) - 1] = 0;sendto(sfd, &buf, sizeof(buf), 0, (struct sockaddr *)&sin, addrlen);// 向子进程发送信息}}// 4、关闭文件描述符close(sfd);return 0;
}
2、客服端
#include <myhead.h>
#define SER_PORT 6666 // 与服务器保持一致
#define SER_IP "192.168.179.128" // 服务器ip地址// 用于信息发送的结构体
struct msgTyp
{char type; // 信息类型 L-》注册名 T-》聊天信息 Q-》退出char name[20]; // 注册名char msg[256]; // 聊天信息
};int main(int argc, char const *argv[])
{// 1、 创建用于通信的套接字文件描述符int cfd = socket(AF_INET, SOCK_DGRAM, 0);if (cfd == -1){perror("socket error");return -1;}printf("cfd = %d\n", cfd);// 2、信息发送// 2.1数据结构体定义struct msgTyp buf;bzero(&buf, 0);// 2.2 填充服务器地址信息结构体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地址socklen_t seraddr_len = sizeof(sin); // 服务器信息结构体大小// 2.3 注册buf.type = 'L'; // 指定消息类型printf("注册用户名:");fgets(buf.name, sizeof(buf.name), stdin);buf.name[strlen(buf.name) - 1] = 0;strcpy(buf.msg, "登录");// 向服务器发送登录信息sendto(cfd, &buf, sizeof(buf), 0, (struct sockaddr *)&sin, seraddr_len);// 3 创建父子进程用于处理不同工作pid_t pid = 0;if (-1 == (pid = fork())){perror("fork error");return -1;}// 子进程,用于接收信息if (0 == pid){while (1){if (-1 == recvfrom(cfd, &buf, sizeof(buf), 0, NULL, NULL)){perror("recvfrom error");return -1;}// 打印接收到的信息printf("[%s]:%s\n", buf.name, buf.msg);}}else if (0 < pid) // 父进程,用于向其他客服端发送信息{while (1){bzero(&buf, 0); // 清空容器,以保证信息的准确性printf("输入信息:");fgets(buf.msg, 256, stdin);buf.msg[strlen(buf.msg) - 1] = 0;if (!strcmp(buf.msg, "quit")){buf.type = 'Q';strcpy(buf.msg, "退出群聊");sendto(cfd, &buf, sizeof(buf), 0, (struct sockaddr *)&sin, seraddr_len);break;}else{buf.type = 'T';// 发送信息sendto(cfd, &buf, sizeof(buf), 0, (struct sockaddr *)&sin, seraddr_len);}}// 退出子进程kill(pid, SIGKILL);wait(NULL); // 阻塞回收子进程资源}// 3、关闭套接字close(cfd);return 0;
}