实验目标:模拟一个分布式计算系统,发布者Server:仅1个,它用于发布计算任务。承担者Client:多个,用于向发布者请求任务,发布者向其发布计算数据后,进行本地计算,完成后,向发布者提交结果。
每次传输的内容规定如下:
字节位置 | 1 | 2 | 3 | 4... |
---|---|---|---|---|
传输内容 | 校验码 | 命令码 | 承担者编号 | 数据部分... |
校验码计算方法:
目前直接填充24即可,没有其他说明。
命令码说明
CMD_HELLO
,注册,C->S,仅1次,数据交互由此开始。其格式为,首部的编号为0,数据部分组成为:数据长度(1B),C主动发送的信息,此处为主机名称。
CMD_HELLOOK
,分配编号,S->C,在收到CMD_HELLO后发送,仅1次,编号部分为S分配的结果,数据部分为空。
CMD_TASK
,请求计算任务,C->S,多次,数据部分为空。
CMD_TASKOK
,下发计算任务,S->C,多次,在收到CMD_TASK之后,S分配任务,返回数据,数据部分为:计算开始值(4B),计算结束值(4B)。若不存在有效的计算任务,开始值和结束值均为0,否则两者均大于0且结束值>开始值。
CMD_UPLOAD
,上报计算结果,C->S,多次,每次完成计算后进行,数据部分为:计算开始值(4B),计算结束值(4B),计算结果(4B)
CMD_UPLOADOK
,计算结果上报反馈,S->C,在收到UPLOAD之后发送,格式与CMD_UPLOAD完全相同。
CMD_NOTIFY
,使用UDP广播和组播时,S通知所有C,C收到后开始发起CMD_HELLO进行后续通信,仅1次。数据部分为空。
命令码定义
c#define CMD_NOTIFY 1
#define CMD_HELLO 2
#define CMD_HELLOOK 3
#define CMD_TASK 4
#define CMD_TASKOK 5
#define CMD_UPLOAD 6
#define CMD_UPLOADOK 7
sequenceDiagram
Server ->> Client: CMD_NOTIFY 广播到所有Client
Client ->> Server: CMD_HELLO 注册
Server -->> Client: CMD_HELLOOK 分配编号
loop 一次计算周期
Client ->> Server: CMD_TASK 请求计算任务
Server -->> Client: CMD_TASKOK 下发计算任务
Client ->> Server: CMD_UPLOAD 上报计算结果
Server -->> Client: CMD_UPLOADOK 计算结果上报反馈
end
c#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#define CMD_NOTIFY 1
#define CMD_HELLO 2
#define CMD_HELLOOK 3
#define CMD_TASK 4
#define CMD_TASKOK 5
#define CMD_UPLOAD 6
#define CMD_UPLOADOK 7
#define PORT 1324 // 服务端绑定端口
#define IPADDR "192.168.152.17" // 服务端绑定IP
#define CLI_PORT 1325 // 因为CMD_NOTIFY需要广播 而广播需要指定接收者的端口号 所以client也必须指定端口
#define BROADCAST_IP "192.168.152.255" //广播IP
int main(int argc, char *argv[])
{
srand(time(NULL)); // 初始化随机数种子
int server_socket = socket(AF_INET, SOCK_DGRAM, 0);
if (server_socket == -1) {
perror("Create Socket Failed: \n");
return -1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = inet_addr(IPADDR);
int ret = bind(server_socket, (struct sockaddr*)&addr, sizeof(addr));
if (0 > ret) {
perror("Bind Failed: \n");
close(server_socket);
return -1;
}
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
ssize_t bytes_send;
ssize_t bytes_recv;
char buffer[1024];
memset(buffer, 0, sizeof(buffer)); // 清空缓存区
printf("Server is Ready!\n");
// 先广播CMD_NOTIFY
int val = 1;
if (setsockopt(server_socket, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)) == -1) {
perror("Boardcast Denied: \n");
close(server_socket);
return -1;
}
client_addr.sin_family = AF_INET;
client_addr.sin_port = htons(CLI_PORT);
client_addr.sin_addr.s_addr = inet_addr(BROADCAST_IP);
buffer[0] = 24;
buffer[1] = CMD_NOTIFY;
buffer[2] = 0;
if (gethostname(&buffer[3], 1021) == -1) {
strcpy(&buffer[3], "Unknown Host");
}
bytes_send = sendto(server_socket, buffer, 1024, 0, (struct sockaddr*)&client_addr, client_len);
if (bytes_send == -1) {
perror("Sending CMD_NOTIFY failed: \n");
close(server_socket);
return -1;
}
printf("CMD_NOTIFY is Sent\n");
memset(buffer, 0, sizeof(buffer)); // 清空缓存区
// 进入循环 开始接收消息并且返回
while (1) {
// 开始接收CMD_HELLO消息
bytes_recv = recvfrom(server_socket, buffer, sizeof(buffer), 0, (struct sockaddr*)&client_addr, &client_len);
if (bytes_recv == -1) {
perror("Receive CMD_HELLO Error: \n");
continue;
}
if (buffer[0] != 24 || buffer[1] != CMD_HELLO || buffer[2] != 0) {
printf("%d %d %d\n", buffer[0], buffer[1], buffer[2]);
printf("Is Not Allowed CMD_HELLO \n");
continue;
}
// 查用户ip 端口和主机名
char client_ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(client_addr.sin_addr), client_ip, INET_ADDRSTRLEN);
int clinet_port = ntohs(client_addr.sin_port);
printf("Client ip: %s, port: %d\n", client_ip, clinet_port);
printf("Client hostname: %.*s\n", 1021, &buffer[3]);
memset(buffer, 0, sizeof(buffer)); // 清空缓冲区
// 开始发送CMD_HELLOOK
buffer[0] = 24;
buffer[1] = CMD_HELLOOK;
buffer[2] = 0;
bytes_send = sendto(server_socket, buffer, 1024, 0, (struct sockaddr*)&client_addr, client_len);
if (bytes_send == -1) {
perror("Sending CMD_HELLOOK Error: \n");
} else {
break;
}
}
while(1) {
while(1) {
// 开始接收CMD_TASK消息
bytes_recv = recvfrom(server_socket, buffer, sizeof(buffer), 0, (struct sockaddr*)&client_addr, &client_len);
if (bytes_recv == -1) {
perror("Receive CMD_TASK Error: \n");
continue;
}
if (buffer[0] != 24 || buffer[1] != CMD_TASK || buffer[2] != 0) {
printf("%d %d %d\n", buffer[0], buffer[1], buffer[2]);
printf("Is Not Allowed CMD_TASK \n");
continue;
} else {
break;
}
}
memset(buffer, 0, sizeof(buffer)); // 清空缓存区
while(1) {
// 开始下发任务 CMD_TASKOK
buffer[0] = 24;
buffer[1] = CMD_TASKOK;
buffer[2] = 0;
*((u_int32_t*)(buffer + 3)) = htonl(rand()); // 286331153 测试数字
*((u_int32_t*)(buffer + 7)) = htonl(rand()); // 572662306
bytes_send = sendto(server_socket, buffer, 1024, 0, (struct sockaddr*)&client_addr, client_len);
if (bytes_send == -1) {
perror("Sending CMD_TASKOK Error: \n");
} else {
break;
}
}
memset(buffer, 0, sizeof(buffer)); // 清空缓存区
while(1) {
// 开始接收CMD_UPLOAD消息
bytes_recv = recvfrom(server_socket, buffer, sizeof(buffer), 0, (struct sockaddr*)&client_addr, &client_len);
if (bytes_recv == -1) {
perror("Receive CMD_UPLOAD Error: \n");
continue;
}
if (buffer[0] != 24 || buffer[1] != CMD_UPLOAD || buffer[2] != 0) {
printf("%d %d %d\n", buffer[0], buffer[1], buffer[2]);
printf("Is Not Allowed CMD_UPLOAD \n");
} else {
break;
}
}
u_int32_t num1, num2, num3;
memcpy(&num1, buffer + 3, sizeof(u_int32_t));
memcpy(&num2, buffer + 3 + sizeof(u_int32_t), sizeof(u_int32_t));
memcpy(&num3, buffer + 3 + 2 * sizeof(u_int32_t), sizeof(u_int32_t));
num1 = ntohl(num1);
num2 = ntohl(num2);
num3 = ntohl(num3);
printf("Calc Finished: %u %u %u\n", num1, num2, num3);
while(1) {
// 开始回复CMD_UPLOADOK
buffer[1] = CMD_UPLOADOK;
bytes_send = sendto(server_socket, buffer, 1024, 0, (struct sockaddr*)&client_addr, client_len);
if (bytes_send == -1) {
perror("Sending CMD_TASKOK Error: \n");
} else {
break;
}
}
memset(buffer, 0, sizeof(buffer)); // 清空缓存区
}
close(server_socket);
return 0;
}
c#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#define CMD_NOTIFY 1
#define CMD_HELLO 2
#define CMD_HELLOOK 3
#define CMD_TASK 4
#define CMD_TASKOK 5
#define CMD_UPLOAD 6
#define CMD_UPLOADOK 7
#define PORT 1325 // 客户端绑定端口
#define IPADDR "192.168.152.17" // 客户端绑定IP
int main(int argc, char const *argv[])
{
// 创建客户端套接字
int socketfd = socket(AF_INET, SOCK_DGRAM, 0);
if (socketfd == -1) {
perror("Create Socket failed: \n");
return -1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
int ret = bind(socketfd, (struct sockaddr*)&addr, sizeof(addr));
if (0 > ret) {
perror("Bind Failed: \n");
close(socketfd);
return -1;
}
// 创建服务器端地址
struct sockaddr_in server_addr;
socklen_t server_len = sizeof(server_addr);
char buffer[1024];
u_int32_t result;
printf("Client is Ready!\n");
printf("Waiting for CMD_NOTIFY...\n");
while (1) {
// 开始接收CMD_NOTIFY
ssize_t bytes_recv = recvfrom(socketfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&server_addr, &server_len);
if (bytes_recv == -1) {
perror("Receiving Data Failed: \n");
continue;
}
if (buffer[0] != 24 || buffer[1] != CMD_NOTIFY || buffer[2] != 0) {
printf("%d %d %d\n", buffer[0], buffer[1], buffer[2]);
printf("Is Not Allowed CMD_NOTIFY \n");
continue;
} else {
break;
}
}
// 查服务端ip 端口和主机名
char server_ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(server_addr.sin_addr), server_ip, INET_ADDRSTRLEN);
int server_port = ntohs(server_addr.sin_port);
printf("Server ip: %s, port: %d\n", server_ip, server_port);
printf("Server hostname: %.*s\n", 1021, &buffer[3]);
memset(buffer, 0, sizeof(buffer)); // 清空缓冲区
while(1) {
// 开始发送CMD_HELLO
buffer[0] = 24;
buffer[1] = CMD_HELLO;
buffer[2] = 0;
if (gethostname(&buffer[3], 1021) == -1) {
strcpy(&buffer[3], "Unknown Host");
}
ssize_t bytes_send = sendto(socketfd, buffer, 1024, 0, (struct sockaddr*)&server_addr, server_len);
if (bytes_send == -1) {
perror("Sending CMD_HELLO failed: \n");
continue;
} else {
break;
}
}
memset(buffer, 0, sizeof(buffer)); // 清空缓冲区
while(1) {
// 开始接收CMD_HELLOOK
ssize_t bytes_recv = recvfrom(socketfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&server_addr, &server_len);
if (bytes_recv == -1) {
perror("Receiving Data Failed: \n");
continue;
}
if (buffer[0] != 24 || buffer[1] != CMD_HELLOOK || buffer[2] != 0) {
printf("%d %d %d\n", buffer[0], buffer[1], buffer[2]);
printf("Is Not Allowed CMD_HELLOOK \n");
continue;
} else {
break;
}
}
memset(buffer, 0, sizeof(buffer)); // 清空缓冲区
while(1) {
while(1) {
// 开始发送CMD_TASK
buffer[0] = 24;
buffer[1] = CMD_TASK;
buffer[2] = 0;
ssize_t bytes_send = sendto(socketfd, buffer, 1024, 0, (struct sockaddr*)&server_addr, server_len);
if (bytes_send == -1) {
perror("Sending CMD_HELLO failed: \n");
continue;
} else {
break;
}
}
memset(buffer, 0, sizeof(buffer)); // 清空缓冲区
while(1) {
// 开始接收CMD_TASKOK
ssize_t bytes_recv = recvfrom(socketfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&server_addr, &server_len);
if (bytes_recv == -1) {
perror("Receive CMD_TASKOK Error: \n");
continue;
}
if (buffer[0] != 24 || buffer[1] != CMD_TASKOK || buffer[2] != 0) {
printf("%d %d %d\n", buffer[0], buffer[1], buffer[2]);
printf("Is Not Allowed CMD_TASKOK \n");
continue;
} else {
break;
}
}
u_int32_t num1, num2;
memcpy(&num1, buffer + 3, sizeof(u_int32_t));
memcpy(&num2, buffer + 3 + sizeof(u_int32_t), sizeof(u_int32_t));
num1 = ntohl(num1);
num2 = ntohl(num2);
result = num1 + num2;
printf("Calc Finished: %u %u %u\n", num1, num2, result);
while(1) {
// 开始发送CMD_UPLOAD
buffer[1] = CMD_UPLOAD;
*((u_int32_t*)(buffer + 11)) = htonl(result);
ssize_t bytes_send = sendto(socketfd, buffer, 1024, 0, (struct sockaddr*)&server_addr, server_len);
if (bytes_send == -1) {
perror("Sending CMD_UPLOAD failed: \n");
continue;
} else {
break;
}
}
memset(buffer, 0, sizeof(buffer)); // 清空缓冲区
while(1) {
// 开始接收CMD_UPLOADOK
ssize_t bytes_recv = recvfrom(socketfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&server_addr, &server_len);
if (bytes_recv == -1) {
perror("Receive CMD_UPLOADOK Error: \n");
continue;
}
if (buffer[0] != 24 || buffer[1] != CMD_UPLOADOK || buffer[2] != 0) {
printf("%d %d %d\n", buffer[0], buffer[1], buffer[2]);
printf("Is Not Allowed CMD_UPLOADOK \n");
continue;
} else {
break;
}
}
}
// 关闭套接字
close(socketfd);
return 0;
}
服务端:
客户端:
这个实验的代码的运行过程给谁发一定想明白。在WSL自己给自己发的情况下:
第一次的CMD_NOTIFY是广播,是要给同一网段的所有设备发的,所以WSL可以发送到Windows层面,Windows也抓得到广播的包。
之后在明确了客户端IP后,收发对象就全是那一个IP了,这种情况下数据包不会出WSL,只会在Linux的网卡内转。
bashsudo apt install wireshark
sudo dpkg-reconfigure wireshark-common
sudo chmod +x /usr/bin/dumpcap
第二步是允许非root用户抓包;最后这一步不做的话,WireShark找不到Linux上的网卡。
最上面的过滤器里写表达式,如udp.port==1324
,ip.dst==192.168.1.11
等等。
c#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#define CMD_NOTIFY 1
#define CMD_HELLO 2
#define CMD_HELLOOK 3
#define CMD_TASK 4
#define CMD_TASKOK 5
#define CMD_UPLOAD 6
#define CMD_UPLOADOK 7
#define PORT 1324
#define IPADDR "192.168.152.17"
#define CLI_PORT 1325 // 因为CMD_NOTIFY需要广播 而广播需要指定接收者的端口号 所以client也必须指定端口
#define BROADCAST_IP "192.168.152.255"
// 存储客户端信息 包括客户端地址和编号
struct ClientInfo
{
struct sockaddr_in client_addr;
int client_id;
};
// 保存客户端
int newClient(struct ClientInfo client_info_array[], struct sockaddr_in new_client_addr) {
for (int i = 0; i < 10; i++) {
if (client_info_array[i].client_id == -1) {
client_info_array[i].client_addr = new_client_addr;
client_info_array[i].client_id = i;
return i;
}
}
return -1;
}
// 回复CMD_HELLOOK
void replyCMD_HELLOOK(char buffer[], int socket, struct sockaddr_in client_addr, int client_id) {
// 打印客户端信息
char client_ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(client_addr.sin_addr), client_ip, INET_ADDRSTRLEN);
int clinet_port = ntohs(client_addr.sin_port);
printf("Client ip: %s, port: %d\n", client_ip, clinet_port);
printf("Client hostname: %.*s\n", 1021, &buffer[3]);
printf("Client ID: %d\n", client_id);
memset(buffer, 0, sizeof(&buffer)); // 清空缓冲区
// 开始发送CMD_HELLOOK
buffer[0] = 24;
buffer[1] = CMD_HELLOOK;
buffer[2] = client_id;
while(1) {
ssize_t bytes_send = sendto(socket, buffer, 1024, 0, (struct sockaddr*)&client_addr, sizeof(client_addr));
if (bytes_send == -1) {
perror("Sending CMD_HELLOOK Error: \n");
} else {
memset(buffer, 0, sizeof(&buffer)); // 清空缓冲区
break;
}
}
}
// 回复CMD_TASKOK
void replyCMD_TASKOK(char buffer[], int socket, struct sockaddr_in client_addr, int client_id) {
memset(buffer, 0, sizeof(&buffer)); // 清空缓存区
// 开始下发任务 CMD_TASKOK
buffer[0] = 24;
buffer[1] = CMD_TASKOK;
buffer[2] = client_id;
*((u_int32_t*)(buffer + 3)) = htonl(rand()); // 286331153 测试数字
*((u_int32_t*)(buffer + 7)) = htonl(rand()); // 572662306
while(1) {
ssize_t bytes_send = sendto(socket, buffer, 1024, 0, (struct sockaddr*)&client_addr, sizeof(client_addr));
if (bytes_send == -1) {
perror("Sending CMD_TASKOK Error: \n");
} else {
memset(buffer, 0, sizeof(&buffer)); // 清空缓存区
break;
}
}
}
// 回复CMD_UPLOADOK
void replyCMD_UPLOADOK(char buffer[], int socket, struct sockaddr_in client_addr, int client_id) {
// 打印计算结果
u_int32_t num1, num2, num3;
memcpy(&num1, buffer + 3, sizeof(u_int32_t));
memcpy(&num2, buffer + 3 + sizeof(u_int32_t), sizeof(u_int32_t));
memcpy(&num3, buffer + 3 + 2 * sizeof(u_int32_t), sizeof(u_int32_t));
num1 = ntohl(num1);
num2 = ntohl(num2);
num3 = ntohl(num3);
printf("Calc Finished: %u %u %u\n", num1, num2, num3);
while(1) {
// 开始回复CMD_UPLOADOK
buffer[1] = CMD_UPLOADOK;
ssize_t bytes_send = sendto(socket, buffer, 1024, 0, (struct sockaddr*)&client_addr, sizeof(client_addr));
if (bytes_send == -1) {
perror("Sending CMD_TASKOK Error: \n");
} else {
memset(buffer, 0, sizeof(&buffer)); // 清空缓存区
break;
}
}
}
int main(int argc, char const *argv[])
{
struct ClientInfo client_array[10];
// 初始化
for (int i = 0; i < 10; i++) {
client_array[i].client_id = -1;
}
srand(time(NULL)); // 初始化随机数种子
int server_socket = socket(AF_INET, SOCK_DGRAM, 0);
if (server_socket == -1) {
perror("Create Socket Failed: \n");
return -1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = inet_addr(IPADDR);
int ret = bind(server_socket, (struct sockaddr*)&addr, sizeof(addr));
if (0 > ret) {
perror("Bind Failed: \n");
close(server_socket);
return -1;
}
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
ssize_t bytes_send;
ssize_t bytes_recv;
char buffer[1024];
memset(buffer, 0, sizeof(buffer)); // 清空缓存区
printf("Server is Ready!\n");
// 先广播CMD_NOTIFY
int val = 1;
if (setsockopt(server_socket, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)) == -1) {
perror("Boardcast Denied: \n");
close(server_socket);
return -1;
}
client_addr.sin_family = AF_INET;
client_addr.sin_port = htons(CLI_PORT);
client_addr.sin_addr.s_addr = inet_addr(BROADCAST_IP);
buffer[0] = 24;
buffer[1] = CMD_NOTIFY;
buffer[2] = 0;
if (gethostname(&buffer[3], 1021) == -1) {
strcpy(&buffer[3], "Unknown Host");
}
bytes_send = sendto(server_socket, buffer, 1024, 0, (struct sockaddr*)&client_addr, client_len);
if (bytes_send == -1) {
perror("Sending CMD_NOTIFY failed: \n");
close(server_socket);
return -1;
}
printf("CMD_NOTIFY is Sent\n");
memset(buffer, 0, sizeof(&buffer)); // 清空缓存区
while(1) {
// 开始接收消息
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
bytes_recv = recvfrom(server_socket, buffer, sizeof(buffer), 0, (struct sockaddr*)&client_addr, &client_len);
if (bytes_recv == -1) {
perror("Receive Message Error: \n");
continue;
}
if (buffer[0] != 24) {
printf("It's Not Allowed Message \n");
continue;
}
// 接收CMD_HELLO 注册客户端并且调用函数回复CMD_HELLOOK
if (buffer[1] == CMD_HELLO && buffer[2] == 0) {
int client_id = newClient(client_array, client_addr);
if (client_id == -1) {
printf("client_array is Full");
continue;
}
replyCMD_HELLOOK(buffer, server_socket, client_array[client_id].client_addr, client_id);
}
// 接收CMD_TASK 并且调用函数回复CMD_TASKOK
if (buffer[1] == CMD_TASK) {
int client_id = buffer[2];
if (client_id >= 10) {
printf("Client ID is not Allowed\n");
continue;
}
replyCMD_TASKOK(buffer, server_socket, client_array[client_id].client_addr, client_id);
}
// 接收CMD_UPLOAD 并且调用函数回复CMD_UPLOADOK
if (buffer[1] == CMD_UPLOAD) {
int client_id = buffer[2];
if (client_id >= 10) {
printf("Client ID is not Allowed\n");
continue;
}
replyCMD_UPLOADOK(buffer, server_socket, client_array[client_id].client_addr, client_id);
}
}
close(server_socket);
return 0;
}
c#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#define CMD_NOTIFY 1
#define CMD_HELLO 2
#define CMD_HELLOOK 3
#define CMD_TASK 4
#define CMD_TASKOK 5
#define CMD_UPLOAD 6
#define CMD_UPLOADOK 7
#define PORT 1325
#define IPADDR "192.168.152.17"
int main(int argc, char const *argv[])
{
// 创建客户端套接字
int socketfd = socket(AF_INET, SOCK_DGRAM, 0);
if (socketfd == -1) {
perror("Create Socket failed: \n");
return -1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
int ret = bind(socketfd, (struct sockaddr*)&addr, sizeof(addr));
if (0 > ret) {
perror("Bind Failed: \n");
close(socketfd);
return -1;
}
// 创建服务器端地址
struct sockaddr_in server_addr;
socklen_t server_len = sizeof(server_addr);
char buffer[1024];
u_int32_t result;
int client_id;
printf("Client is Ready!\n");
printf("Waiting for CMD_NOTIFY...\n");
while (1) {
// 开始接收CMD_NOTIFY
ssize_t bytes_recv = recvfrom(socketfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&server_addr, &server_len);
if (bytes_recv == -1) {
perror("Receiving Data Failed: \n");
continue;
}
if (buffer[0] != 24 || buffer[1] != CMD_NOTIFY || buffer[2] != 0) {
printf("%d %d %d\n", buffer[0], buffer[1], buffer[2]);
printf("Is Not Allowed CMD_NOTIFY \n");
continue;
} else {
break;
}
}
// 查服务端ip 端口和主机名
char server_ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(server_addr.sin_addr), server_ip, INET_ADDRSTRLEN);
int server_port = ntohs(server_addr.sin_port);
printf("Server ip: %s, port: %d\n", server_ip, server_port);
printf("Server hostname: %.*s\n", 1021, &buffer[3]);
memset(buffer, 0, sizeof(buffer)); // 清空缓冲区
while(1) {
// 开始发送CMD_HELLO
buffer[0] = 24;
buffer[1] = CMD_HELLO;
buffer[2] = 0;
if (gethostname(&buffer[3], 1021) == -1) {
strcpy(&buffer[3], "Unknown Host");
}
ssize_t bytes_send = sendto(socketfd, buffer, 1024, 0, (struct sockaddr*)&server_addr, server_len);
if (bytes_send == -1) {
perror("Sending CMD_HELLO failed: \n");
continue;
} else {
break;
}
}
memset(buffer, 0, sizeof(buffer)); // 清空缓冲区
while(1) {
// 开始接收CMD_HELLOOK
ssize_t bytes_recv = recvfrom(socketfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&server_addr, &server_len);
if (bytes_recv == -1) {
perror("Receiving Data Failed: \n");
continue;
}
if (buffer[0] != 24 || buffer[1] != CMD_HELLOOK || buffer[2] != 0) {
printf("%d %d %d\n", buffer[0], buffer[1], buffer[2]);
printf("Is Not Allowed CMD_HELLOOK \n");
continue;
} else {
client_id = buffer[2];
printf("Client ID is %d\n", client_id);
break;
}
}
memset(buffer, 0, sizeof(buffer)); // 清空缓冲区
while(1) {
while(1) {
// 开始发送CMD_TASK
buffer[0] = 24;
buffer[1] = CMD_TASK;
buffer[2] = client_id;
ssize_t bytes_send = sendto(socketfd, buffer, 1024, 0, (struct sockaddr*)&server_addr, server_len);
if (bytes_send == -1) {
perror("Sending CMD_HELLO failed: \n");
continue;
} else {
break;
}
}
memset(buffer, 0, sizeof(buffer)); // 清空缓冲区
while(1) {
// 开始接收CMD_TASKOK
ssize_t bytes_recv = recvfrom(socketfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&server_addr, &server_len);
if (bytes_recv == -1) {
perror("Receive CMD_TASKOK Error: \n");
continue;
}
if (buffer[0] != 24 || buffer[1] != CMD_TASKOK || buffer[2] != client_id) {
printf("%d %d %d\n", buffer[0], buffer[1], buffer[2]);
printf("Is Not Allowed CMD_TASKOK \n");
continue;
} else {
break;
}
}
u_int32_t num1, num2;
memcpy(&num1, buffer + 3, sizeof(u_int32_t));
memcpy(&num2, buffer + 3 + sizeof(u_int32_t), sizeof(u_int32_t));
num1 = ntohl(num1);
num2 = ntohl(num2);
result = num1 + num2;
printf("Calc Finished: %u %u %u\n", num1, num2, result);
sleep(1);
printf("Sleep Finished\n");
while(1) {
// 开始发送CMD_UPLOAD
buffer[1] = CMD_UPLOAD;
*((u_int32_t*)(buffer + 11)) = htonl(result);
ssize_t bytes_send = sendto(socketfd, buffer, 1024, 0, (struct sockaddr*)&server_addr, server_len);
if (bytes_send == -1) {
perror("Sending CMD_UPLOAD failed: \n");
continue;
} else {
break;
}
}
memset(buffer, 0, sizeof(buffer)); // 清空缓冲区
while(1) {
// 开始接收CMD_UPLOADOK
ssize_t bytes_recv = recvfrom(socketfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&server_addr, &server_len);
if (bytes_recv == -1) {
perror("Receive CMD_UPLOADOK Error: \n");
continue;
}
if (buffer[0] != 24 || buffer[1] != CMD_UPLOADOK || buffer[2] != client_id) {
printf("%d %d %d\n", buffer[0], buffer[1], buffer[2]);
printf("Is Not Allowed CMD_UPLOADOK \n");
continue;
} else {
break;
}
}
}
// 关闭套接字
close(socketfd);
return 0;
}
Ctrl + Shift + p快捷键搜索remote或者ssh,就能找到一个打开SSH配置文件的选项:
进去之后按这个格式写配置信息,公钥部分之后会说。
(主机,主机名,用户名,端口,默认验证方式,身份验证文件,是否代理转发)
回到要开SSH的Linux系统中,编辑/etc/ssh/sshd_config文件(假设ssh已经安装),示例如下:
# This is the sshd server system-wide configuration file. See # sshd_config(5) for more information. # This sshd was compiled with PATH=/usr/local/bin:/usr/bin:/bin:/usr/games # The strategy used for options in the default sshd_config shipped with # OpenSSH is to specify options with their default value where # possible, but leave them commented. Uncommented options override the # default value. Include /etc/ssh/sshd_config.d/*.conf #Port 22 这里是端口 默认22 #AddressFamily any #ListenAddress 0.0.0.0 监听IP ListenAddress 192.168.234.34 #ListenAddress :: 这是本地地址的另一种写法 #HostKey /etc/ssh/ssh_host_rsa_key #HostKey /etc/ssh/ssh_host_ecdsa_key #HostKey /etc/ssh/ssh_host_ed25519_key # Ciphers and keying #RekeyLimit default none # Logging #SyslogFacility AUTH #LogLevel INFO # Authentication: #LoginGraceTime 2m #PermitRootLogin prohibit-password PermitRootLogin yes 允许root用户通过ssh登录 #StrictModes yes #MaxAuthTries 6 #MaxSessions 10 #PubkeyAuthentication yes PubkeyAuthentication yes 允许公钥验证 # Expect .ssh/authorized_keys2 to be disregarded by default in future. AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2 验证密钥文件 #AuthorizedPrincipalsFile none #AuthorizedKeysCommand none #AuthorizedKeysCommandUser nobody # For this to work you will also need host keys in /etc/ssh/ssh_known_hosts #HostbasedAuthentication no # Change to yes if you don't trust ~/.ssh/known_hosts for # HostbasedAuthentication #IgnoreUserKnownHosts no # Don't read the user's ~/.rhosts and ~/.shosts files #IgnoreRhosts yes # To disable tunneled clear text passwords, change to no here! #PasswordAuthentication yes PasswordAuthentication yes #PermitEmptyPasswords no # Change to yes to enable challenge-response passwords (beware issues with # some PAM modules and threads) KbdInteractiveAuthentication no # Kerberos options #KerberosAuthentication no #KerberosOrLocalPasswd yes #KerberosTicketCleanup yes #KerberosGetAFSToken no # GSSAPI options #GSSAPIAuthentication no #GSSAPICleanupCredentials yes #GSSAPIStrictAcceptorCheck yes #GSSAPIKeyExchange no # Set this to 'yes' to enable PAM authentication, account processing, # and session processing. If this is enabled, PAM authentication will # be allowed through the KbdInteractiveAuthentication and # PasswordAuthentication. Depending on your PAM configuration, # PAM authentication via KbdInteractiveAuthentication may bypass # the setting of "PermitRootLogin prohibit-password". # If you just want the PAM account and session checks to run without # PAM authentication, then enable this but set PasswordAuthentication # and KbdInteractiveAuthentication to 'no'. UsePAM yes #AllowAgentForwarding yes #AllowTcpForwarding yes #GatewayPorts no X11Forwarding yes #X11DisplayOffset 10 #X11UseLocalhost yes #PermitTTY yes PrintMotd no #PrintLastLog yes #TCPKeepAlive yes #PermitUserEnvironment no #Compression delayed #ClientAliveInterval 0 #ClientAliveCountMax 3 #UseDNS no #PidFile /run/sshd.pid #MaxStartups 10:30:100 #PermitTunnel no #ChrootDirectory none #VersionAddendum none # no default banner path #Banner none # Allow client to pass locale environment variables AcceptEnv LANG LC_* # override default of no subsystems Subsystem sftp /usr/lib/openssh/sftp-server # Example of overriding settings on a per-user basis #Match User anoncvs # X11Forwarding no # AllowTcpForwarding no # PermitTTY no # ForceCommand cvs server
然后systemctl restart ssh
重新启动(这条命令随着系统不同而可能不同)SSH服务。之后可以在别的地方来测试这个端口了:telnet 192.168.234.34 22
。
提示
这条命令需要在Windows功能中启用telnet客户端。
正常的测试结果:
如果没通的话,就要考虑Linux端的防火墙,有些Linux(比如Kali)会默认将22端口ban掉,这时候就要配置或者关掉防火墙:
以Kali为例 apt install ufw 第一次配置防火墙需要装 ufw disable 关闭防火墙 ufw allow 22/tcp 允许22端口tcp连接
剩下的看图吧。
这个时候VS Code已经可以通过SSH连接Kali了,不过可以通过RSA密钥的方式免于输入密码。先在Windows的cmd里输入ssh-keygen -t rsa -C "3090309265@qq.com"
(后面的邮箱随意),之后一路回车即可。
之后在Windows用户文件夹下的.ssh文件夹下找到公私钥文件id_rsa和id_rsa.pub:
将id_rsa.pub重命名成authorized_keys,放到Linux下的/root/.ssh文件夹下:
Linux这边以防万一再修改下权限:
bashchmod 700 /root
chmod 700 /root/.ssh
chmod 644 /root/.ssh/authorized_keys
之后回到VS Code的配置文件里,把身份验证文件这部分写上,文件路径指向id_rsa即可。到这一步就配置完成了,配置好的Linux可以在这里找到:
如果只是安装了WSL2,没有配置防火墙的话,Hyper-V自带的防火墙会禁掉所有的入站连接,就像这样:
数据包发是发到了,但是没转发给WSL,需要按微软官方的说法执行命令。
bashSet-NetFirewallHyperVVMSetting -Name ‘{40E0AC32-46A5-438A-A0B2-2B479E8F2E90}’ -DefaultInboundAction Allow
或
bashNew-NetFirewallHyperVRule -Name MyWebServer -DisplayName “My Web Server” -Direction Inbound -VMCreatorId “{40E0AC32-46A5-438A-A0B2-2B479E8F2E90}” -Protocol TCP -LocalPorts 80
配置Hyper-V防火墙说明,详情见Microsoft Learn | Hyper-V防火墙
Debian刚安装好的时候apt update
有可能会遇到TLS握手过不去的情况,需要重新安装这个sudo apt install apt-transport-https ca-certificates
,但是又会陷入到先安装但过不去TLS握手,先修TLS握手要求先安装的怪圈里。
解决方法是换源的地址别用https,先都用http,比如下面这段配置信息:
deb http://mirrors.aliyun.com/debian/ bookworm main non-free non-free-firmware contrib deb-src http://mirrors.aliyun.com/debian/ bookworm main non-free non-free-firmware contrib deb http://mirrors.aliyun.com/debian-security/ bookworm-security main deb-src http://mirrors.aliyun.com/debian-security/ bookworm-security main deb http://mirrors.aliyun.com/debian/ bookworm-updates main non-free non-free-firmware contrib deb-src http://mirrors.aliyun.com/debian/ bookworm-updates main non-free non-free-firmware contrib deb http://mirrors.aliyun.com/debian/ bookworm-backports main non-free non-free-firmware contrib deb-src http://mirrors.aliyun.com/debian/ bookworm-backports main non-free non-free-firmware contrib
换过源之后再把上面那个安装了,安装好之后再换回https:
deb https://mirrors.aliyun.com/debian/ bookworm main non-free non-free-firmware contrib deb-src https://mirrors.aliyun.com/debian/ bookworm main non-free non-free-firmware contrib deb https://mirrors.aliyun.com/debian-security/ bookworm-security main deb-src https://mirrors.aliyun.com/debian-security/ bookworm-security main deb https://mirrors.aliyun.com/debian/ bookworm-updates main non-free non-free-firmware contrib deb-src https://mirrors.aliyun.com/debian/ bookworm-updates main non-free non-free-firmware contrib deb https://mirrors.aliyun.com/debian/ bookworm-backports main non-free non-free-firmware contrib deb-src https://mirrors.aliyun.com/debian/ bookworm-backports main non-free non-free-firmware contrib
c#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#define CMD_NOTIFY 1
#define CMD_HELLO 2
#define CMD_HELLOOK 3
#define CMD_TASK 4
#define CMD_TASKOK 5
#define CMD_UPLOAD 6
#define CMD_UPLOADOK 7
#define PORT 19326 // 在这里写服务端的端口
#define IPADDR "192.168.234.17" // 在这里写服务端的ip
#define CLI_PORT 19327 // 因为CMD_NOTIFY需要广播 而广播需要指定接收者的端口号 所以客户端也必须指定端口
#define BROADCAST_IP "192.168.234.255" // 在这里写广播地址
// 存储客户端信息 包括客户端地址和编号
struct ClientInfo
{
struct sockaddr_in client_addr;
int client_id;
};
// 保存客户端
int newClient(struct ClientInfo client_info_array[], struct sockaddr_in new_client_addr) {
for (int i = 0; i < 10; i++) {
if (client_info_array[i].client_id == -1) {
client_info_array[i].client_addr = new_client_addr;
client_info_array[i].client_id = i;
return i;
}
}
return -1;
}
// 回复CMD_HELLOOK
void replyCMD_HELLOOK(char buffer[], int socket, struct sockaddr_in client_addr, int client_id) {
// 打印客户端信息
char client_ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(client_addr.sin_addr), client_ip, INET_ADDRSTRLEN);
int clinet_port = ntohs(client_addr.sin_port);
printf("Client ip: %s, port: %d\n", client_ip, clinet_port);
printf("Client hostname: %.*s\n", 1021, &buffer[3]);
printf("Client ID: %d\n", client_id);
memset(buffer, 0, sizeof(&buffer)); // 清空缓冲区
// 开始发送CMD_HELLOOK
buffer[0] = 24;
buffer[1] = CMD_HELLOOK;
buffer[2] = client_id;
while(1) {
ssize_t bytes_send = sendto(socket, buffer, 1024, 0, (struct sockaddr*)&client_addr, sizeof(client_addr));
if (bytes_send == -1) {
perror("Sending CMD_HELLOOK Error: \n");
} else {
memset(buffer, 0, sizeof(&buffer)); // 清空缓冲区
break;
}
}
}
// 回复CMD_TASKOK
void replyCMD_TASKOK(char buffer[], int socket, struct sockaddr_in client_addr, int client_id) {
memset(buffer, 0, sizeof(&buffer)); // 清空缓存区
// 开始下发任务 CMD_TASKOK
buffer[0] = 24;
buffer[1] = CMD_TASKOK;
buffer[2] = client_id;
*((u_int32_t*)(buffer + 3)) = htonl(rand()); // 286331153 测试数字
*((u_int32_t*)(buffer + 7)) = htonl(rand()); // 572662306
while(1) {
ssize_t bytes_send = sendto(socket, buffer, 1024, 0, (struct sockaddr*)&client_addr, sizeof(client_addr));
if (bytes_send == -1) {
perror("Sending CMD_TASKOK Error: \n");
} else {
memset(buffer, 0, sizeof(&buffer)); // 清空缓存区
break;
}
}
}
// 回复CMD_UPLOADOK
void replyCMD_UPLOADOK(char buffer[], int socket, struct sockaddr_in client_addr, int client_id) {
// 打印计算结果
u_int32_t num1, num2, num3;
memcpy(&num1, buffer + 3, sizeof(u_int32_t));
memcpy(&num2, buffer + 3 + sizeof(u_int32_t), sizeof(u_int32_t));
memcpy(&num3, buffer + 3 + 2 * sizeof(u_int32_t), sizeof(u_int32_t));
num1 = ntohl(num1);
num2 = ntohl(num2);
num3 = ntohl(num3);
char client_ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(client_addr.sin_addr), client_ip, INET_ADDRSTRLEN);
printf("%s Calc Finished: %u + %u = %u\n", client_ip, num1, num2, num3);
while(1) {
// 开始回复CMD_UPLOADOK
buffer[1] = CMD_UPLOADOK;
ssize_t bytes_send = sendto(socket, buffer, 1024, 0, (struct sockaddr*)&client_addr, sizeof(client_addr));
if (bytes_send == -1) {
perror("Sending CMD_TASKOK Error: \n");
} else {
memset(buffer, 0, sizeof(&buffer)); // 清空缓存区
break;
}
}
}
int main(int argc, char const *argv[])
{
struct ClientInfo client_array[10];
// 初始化
for (int i = 0; i < 10; i++) {
client_array[i].client_id = -1;
}
srand(time(NULL)); // 初始化随机数种子
int server_socket = socket(AF_INET, SOCK_DGRAM, 0);
if (server_socket == -1) {
perror("Create Socket Failed: \n");
return -1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = inet_addr(IPADDR);
int ret = bind(server_socket, (struct sockaddr*)&addr, sizeof(addr));
if (0 > ret) {
perror("Bind Failed: \n");
close(server_socket);
return -1;
}
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
ssize_t bytes_send;
ssize_t bytes_recv;
char buffer[1024];
memset(buffer, 0, sizeof(buffer)); // 清空缓存区
printf("Server is Ready!\n");
// 先广播CMD_NOTIFY
int val = 1;
if (setsockopt(server_socket, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)) == -1) {
perror("Boardcast Denied: \n");
close(server_socket);
return -1;
}
client_addr.sin_family = AF_INET;
client_addr.sin_port = htons(CLI_PORT);
client_addr.sin_addr.s_addr = inet_addr(BROADCAST_IP);
buffer[0] = 24;
buffer[1] = CMD_NOTIFY;
buffer[2] = 0;
if (gethostname(&buffer[3], 1021) == -1) {
strcpy(&buffer[3], "Unknown Host");
}
bytes_send = sendto(server_socket, buffer, 1024, 0, (struct sockaddr*)&client_addr, client_len);
if (bytes_send == -1) {
perror("Sending CMD_NOTIFY failed: \n");
close(server_socket);
return -1;
}
printf("CMD_NOTIFY is Sent\n");
memset(buffer, 0, sizeof(&buffer)); // 清空缓存区
while(1) {
// 开始接收消息
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
bytes_recv = recvfrom(server_socket, buffer, sizeof(buffer), 0, (struct sockaddr*)&client_addr, &client_len);
if (bytes_recv == -1) {
perror("Receive Message Error: \n");
continue;
}
if (buffer[0] != 24) {
printf("It's Not Allowed Message \n");
continue;
}
// 接收CMD_HELLO 注册客户端并且调用函数回复CMD_HELLOOK
if (buffer[1] == CMD_HELLO && buffer[2] == 0) {
int client_id = newClient(client_array, client_addr);
if (client_id == -1) {
printf("client_array is Full");
continue;
}
replyCMD_HELLOOK(buffer, server_socket, client_array[client_id].client_addr, client_id);
}
// 接收CMD_TASK 并且调用函数回复CMD_TASKOK
if (buffer[1] == CMD_TASK) {
int client_id = buffer[2];
if (client_id >= 10) {
printf("Client ID is not Allowed\n");
continue;
}
replyCMD_TASKOK(buffer, server_socket, client_array[client_id].client_addr, client_id);
}
// 接收CMD_UPLOAD 并且调用函数回复CMD_UPLOADOK
if (buffer[1] == CMD_UPLOAD) {
int client_id = buffer[2];
if (client_id >= 10) {
printf("Client ID is not Allowed\n");
continue;
}
replyCMD_UPLOADOK(buffer, server_socket, client_array[client_id].client_addr, client_id);
}
}
close(server_socket);
return 0;
}
所有的sleep都是为了不让输出变得太快,以至于完全无法观察。几个客户端之间的sleep的时间也可以进行调整。
c#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#define CMD_NOTIFY 1
#define CMD_HELLO 2
#define CMD_HELLOOK 3
#define CMD_TASK 4
#define CMD_TASKOK 5
#define CMD_UPLOAD 6
#define CMD_UPLOADOK 7
#define PORT 19327 // 在这里写客户端的端口
int main(int argc, char const *argv[])
{
// 创建客户端套接字
int socketfd = socket(AF_INET, SOCK_DGRAM, 0);
if (socketfd == -1) {
perror("Create Socket failed: \n");
return -1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
int ret = bind(socketfd, (struct sockaddr*)&addr, sizeof(addr));
if (0 > ret) {
perror("Bind Failed: \n");
close(socketfd);
return -1;
}
// 创建服务器端地址
struct sockaddr_in server_addr;
socklen_t server_len = sizeof(server_addr);
char buffer[1024];
u_int32_t result;
int client_id; // 保存客户端id
printf("Client is Ready!\n");
printf("Waiting for CMD_NOTIFY...\n");
while (1) {
// 开始接收CMD_NOTIFY
ssize_t bytes_recv = recvfrom(socketfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&server_addr, &server_len);
if (bytes_recv == -1) {
perror("Receiving Data Failed: \n");
continue;
}
if (buffer[0] != 24 || buffer[1] != CMD_NOTIFY || buffer[2] != 0) {
printf("%d %d %d\n", buffer[0], buffer[1], buffer[2]);
printf("Is Not Allowed CMD_NOTIFY \n");
continue;
} else {
break;
}
}
// 查服务端ip 端口和主机名
char server_ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(server_addr.sin_addr), server_ip, INET_ADDRSTRLEN);
int server_port = ntohs(server_addr.sin_port);
printf("Server ip: %s, port: %d\n", server_ip, server_port);
printf("Server hostname: %.*s\n", 1021, &buffer[3]);
memset(buffer, 0, sizeof(buffer)); // 清空缓冲区
while(1) {
sleep(5);
// 开始发送CMD_HELLO
buffer[0] = 24;
buffer[1] = CMD_HELLO;
buffer[2] = 0;
if (gethostname(&buffer[3], 1021) == -1) {
strcpy(&buffer[3], "Unknown Host");
}
ssize_t bytes_send = sendto(socketfd, buffer, 1024, 0, (struct sockaddr*)&server_addr, server_len);
if (bytes_send == -1) {
perror("Sending CMD_HELLO failed: \n");
continue;
} else {
printf("CMD_HELLO is sent \n");
break;
}
}
memset(buffer, 0, sizeof(buffer)); // 清空缓冲区
while(1) {
// 开始接收CMD_HELLOOK
ssize_t bytes_recv = recvfrom(socketfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&server_addr, &server_len);
if (bytes_recv == -1) {
perror("Receiving Data Failed: \n");
continue;
}
if (buffer[0] != 24 || buffer[1] != CMD_HELLOOK) {
printf("%d %d %d\n", buffer[0], buffer[1], buffer[2]);
printf("Is Not Allowed CMD_HELLOOK \n");
continue;
} else {
client_id = buffer[2];
printf("Client ID is %d\n", client_id);
break;
}
}
memset(buffer, 0, sizeof(buffer)); // 清空缓冲区
while(1) {
while(1) {
// 开始发送CMD_TASK
buffer[0] = 24;
buffer[1] = CMD_TASK;
buffer[2] = client_id;
ssize_t bytes_send = sendto(socketfd, buffer, 1024, 0, (struct sockaddr*)&server_addr, server_len);
if (bytes_send == -1) {
perror("Sending CMD_HELLO failed: \n");
continue;
} else {
break;
}
}
memset(buffer, 0, sizeof(buffer)); // 清空缓冲区
while(1) {
// 开始接收CMD_TASKOK
ssize_t bytes_recv = recvfrom(socketfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&server_addr, &server_len);
if (bytes_recv == -1) {
perror("Receive CMD_TASKOK Error: \n");
continue;
}
if (buffer[0] != 24 || buffer[1] != CMD_TASKOK || buffer[2] != client_id) {
printf("%d %d %d\n", buffer[0], buffer[1], buffer[2]);
printf("Is Not Allowed CMD_TASKOK \n");
continue;
} else {
break;
}
}
u_int32_t num1, num2;
memcpy(&num1, buffer + 3, sizeof(u_int32_t));
memcpy(&num2, buffer + 3 + sizeof(u_int32_t), sizeof(u_int32_t));
num1 = ntohl(num1);
num2 = ntohl(num2);
result = num1 + num2;
printf("Calc Finished: %u + %u = %u\n", num1, num2, result);
sleep(1); // Linux下的sleep函数 传入秒数单位是秒 Windows下是毫秒
printf("Sleep Finished\n");
while(1) {
// 开始发送CMD_UPLOAD
buffer[1] = CMD_UPLOAD;
*((u_int32_t*)(buffer + 11)) = htonl(result);
ssize_t bytes_send = sendto(socketfd, buffer, 1024, 0, (struct sockaddr*)&server_addr, server_len);
if (bytes_send == -1) {
perror("Sending CMD_UPLOAD failed: \n");
continue;
} else {
break;
}
}
memset(buffer, 0, sizeof(buffer)); // 清空缓冲区
while(1) {
// 开始接收CMD_UPLOADOK
ssize_t bytes_recv = recvfrom(socketfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&server_addr, &server_len);
if (bytes_recv == -1) {
perror("Receive CMD_UPLOADOK Error: \n");
continue;
}
if (buffer[0] != 24 || buffer[1] != CMD_UPLOADOK || buffer[2] != client_id) {
printf("%d %d %d\n", buffer[0], buffer[1], buffer[2]);
printf("Is Not Allowed CMD_UPLOADOK \n");
continue;
} else {
break;
}
}
}
// 关闭套接字
close(socketfd);
return 0;
}
这次更新了老师给的计算素数个数的要求,还没测试,理论上是通的。
c#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#define CMD_NOTIFY 1
#define CMD_HELLO 2
#define CMD_HELLOOK 3
#define CMD_TASK 4
#define CMD_TASKOK 5
#define CMD_UPLOAD 6
#define CMD_UPLOADOK 7
#define PORT 19326
#define IPADDR "192.168.156.17"
#define CLI_PORT 19327 // 因为CMD_NOTIFY需要广播 而广播需要指定接收者的端口号 所以client也必须指定端口
#define BROADCAST_IP "192.168.156.255"
// 存储客户端信息 包括客户端地址和编号
struct ClientInfo
{
struct sockaddr_in client_addr;
int client_id;
};
// 保存客户端
int newClient(struct ClientInfo client_info_array[], struct sockaddr_in new_client_addr) {
for (int i = 0; i < 10; i++) {
if (client_info_array[i].client_id == -1) {
client_info_array[i].client_addr = new_client_addr;
client_info_array[i].client_id = i;
return i;
}
}
return -1;
}
// 回复CMD_HELLOOK
void replyCMD_HELLOOK(char buffer[], int socket, struct sockaddr_in client_addr, int client_id) {
// 打印客户端信息
char client_ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(client_addr.sin_addr), client_ip, INET_ADDRSTRLEN);
int clinet_port = ntohs(client_addr.sin_port);
printf("Client ip: %s, port: %d\n", client_ip, clinet_port);
printf("Client hostname: %.*s\n", 1021, &buffer[3]);
printf("Client ID: %d\n", client_id);
memset(buffer, 0, sizeof(&buffer)); // 清空缓冲区
// 开始发送CMD_HELLOOK
buffer[0] = 24;
buffer[1] = CMD_HELLOOK;
buffer[2] = client_id;
while(1) {
ssize_t bytes_send = sendto(socket, buffer, 1024, 0, (struct sockaddr*)&client_addr, sizeof(client_addr));
if (bytes_send == -1) {
perror("Sending CMD_HELLOOK Error: \n");
} else {
memset(buffer, 0, sizeof(&buffer)); // 清空缓冲区
break;
}
}
}
// 回复CMD_TASKOK
void replyCMD_TASKOK(char buffer[], int socket, struct sockaddr_in client_addr, int client_id, int start_index) {
memset(buffer, 0, sizeof(&buffer)); // 清空缓存区
// 开始下发任务 CMD_TASKOK
buffer[0] = 24;
buffer[1] = CMD_TASKOK;
buffer[2] = client_id;
if (start_index > 1000000) {
*((u_int32_t*)(buffer + 3)) = htonl(0);
*((u_int32_t*)(buffer + 7)) = htonl(0);
} else {
*((u_int32_t*)(buffer + 3)) = htonl(start_index); // 计算素数的起始位置
*((u_int32_t*)(buffer + 7)) = htonl(start_index + 99); // 计算素数的终止位置
}
while(1) {
ssize_t bytes_send = sendto(socket, buffer, 1024, 0, (struct sockaddr*)&client_addr, sizeof(client_addr));
if (bytes_send == -1) {
perror("Sending CMD_TASKOK Error: \n");
} else {
memset(buffer, 0, sizeof(&buffer)); // 清空缓存区
break;
}
}
}
// 回复CMD_UPLOADOK
int replyCMD_UPLOADOK(char buffer[], int socket, struct sockaddr_in client_addr, int client_id) {
// 打印计算结果
u_int32_t num1, num2, num3;
memcpy(&num1, buffer + 3, sizeof(u_int32_t));
memcpy(&num2, buffer + 3 + sizeof(u_int32_t), sizeof(u_int32_t));
memcpy(&num3, buffer + 3 + 2 * sizeof(u_int32_t), sizeof(u_int32_t));
num1 = ntohl(num1);
num2 = ntohl(num2);
num3 = ntohl(num3);
char client_ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(client_addr.sin_addr), client_ip, INET_ADDRSTRLEN);
printf("%s Calc Finished: %u ~ %u = %u\n", client_ip, num1, num2, num3);
while(1) {
// 开始回复CMD_UPLOADOK
buffer[1] = CMD_UPLOADOK;
ssize_t bytes_send = sendto(socket, buffer, 1024, 0, (struct sockaddr*)&client_addr, sizeof(client_addr));
if (bytes_send == -1) {
perror("Sending CMD_TASKOK Error: \n");
} else {
memset(buffer, 0, sizeof(&buffer)); // 清空缓存区
break;
}
}
return num3;
}
int main(int argc, char const *argv[])
{
struct ClientInfo client_array[10];
// 初始化
for (int i = 0; i < 10; i++) {
client_array[i].client_id = -1;
}
srand(time(NULL)); // 初始化随机数种子
int server_socket = socket(AF_INET, SOCK_DGRAM, 0);
if (server_socket == -1) {
perror("Create Socket Failed: \n");
return -1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = inet_addr(IPADDR);
int ret = bind(server_socket, (struct sockaddr*)&addr, sizeof(addr));
if (0 > ret) {
perror("Bind Failed: \n");
close(server_socket);
return -1;
}
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
ssize_t bytes_send;
ssize_t bytes_recv;
char buffer[1024];
int start_index = 1; // 开始计算素数位置
int result = 0; // 计算结果
memset(buffer, 0, sizeof(buffer)); // 清空缓存区
printf("Server is Ready!\n");
// 先广播CMD_NOTIFY
int val = 1;
if (setsockopt(server_socket, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)) == -1) {
perror("Boardcast Denied: \n");
close(server_socket);
return -1;
}
client_addr.sin_family = AF_INET;
client_addr.sin_port = htons(CLI_PORT);
client_addr.sin_addr.s_addr = inet_addr(BROADCAST_IP);
buffer[0] = 24;
buffer[1] = CMD_NOTIFY;
buffer[2] = 0;
if (gethostname(&buffer[3], 1021) == -1) {
strcpy(&buffer[3], "Unknown Host");
}
bytes_send = sendto(server_socket, buffer, 1024, 0, (struct sockaddr*)&client_addr, client_len);
if (bytes_send == -1) {
perror("Sending CMD_NOTIFY failed: \n");
close(server_socket);
return -1;
}
printf("CMD_NOTIFY is Sent\n");
memset(buffer, 0, sizeof(&buffer)); // 清空缓存区
while(1) {
// 开始接收消息
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
bytes_recv = recvfrom(server_socket, buffer, sizeof(buffer), 0, (struct sockaddr*)&client_addr, &client_len);
if (bytes_recv == -1) {
perror("Receive Message Error: \n");
continue;
}
if (buffer[0] != 24) {
printf("It's Not Allowed Message \n");
continue;
}
// 接收CMD_HELLO 注册客户端并且调用函数回复CMD_HELLOOK
if (buffer[1] == CMD_HELLO && buffer[2] == 0) {
int client_id = newClient(client_array, client_addr);
if (client_id == -1) {
printf("client_array is Full");
continue;
}
replyCMD_HELLOOK(buffer, server_socket, client_array[client_id].client_addr, client_id);
}
// 接收CMD_TASK 并且调用函数回复CMD_TASKOK
if (buffer[1] == CMD_TASK) {
int client_id = buffer[2];
if (client_id >= 10) {
printf("Client ID is not Allowed\n");
continue;
}
replyCMD_TASKOK(buffer, server_socket, client_array[client_id].client_addr, client_id, start_index);
start_index = start_index + 100;
}
// 接收CMD_UPLOAD 并且调用函数回复CMD_UPLOADOK
if (buffer[1] == CMD_UPLOAD) {
int client_id = buffer[2];
if (client_id >= 10) {
printf("Client ID is not Allowed\n");
continue;
}
result = result + replyCMD_UPLOADOK(buffer, server_socket, client_array[client_id].client_addr, client_id);
printf("Result Updated!: %d \n", result);
}
}
close(server_socket);
return 0;
}
c#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#define CMD_NOTIFY 1
#define CMD_HELLO 2
#define CMD_HELLOOK 3
#define CMD_TASK 4
#define CMD_TASKOK 5
#define CMD_UPLOAD 6
#define CMD_UPLOADOK 7
#define PORT 19327
// 判断一个数字是不是素数 是的话返回1 不是的话返回0
int is_prime(int i) {
int j = 0;
for(j = 2; j < i; j++) {
if (i % j == 0)
{
return 0;
}
}
if(j == i) {
return 1;
}
}
int main(int argc, char const *argv[])
{
// 创建客户端套接字
int socketfd = socket(AF_INET, SOCK_DGRAM, 0);
if (socketfd == -1) {
perror("Create Socket failed: \n");
return -1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
int ret = bind(socketfd, (struct sockaddr*)&addr, sizeof(addr));
if (0 > ret) {
perror("Bind Failed: \n");
close(socketfd);
return -1;
}
// 创建服务器端地址
struct sockaddr_in server_addr;
socklen_t server_len = sizeof(server_addr);
char buffer[1024];
u_int32_t result;
int client_id;
printf("Client is Ready!\n");
printf("Waiting for CMD_NOTIFY...\n");
while (1) {
// 开始接收CMD_NOTIFY
ssize_t bytes_recv = recvfrom(socketfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&server_addr, &server_len);
if (bytes_recv == -1) {
perror("Receiving Data Failed: \n");
continue;
}
if (buffer[0] != 24 || buffer[1] != CMD_NOTIFY || buffer[2] != 0) {
printf("%d %d %d\n", buffer[0], buffer[1], buffer[2]);
printf("Is Not Allowed CMD_NOTIFY \n");
continue;
} else {
break;
}
}
// 查服务端ip 端口和主机名
char server_ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(server_addr.sin_addr), server_ip, INET_ADDRSTRLEN);
int server_port = ntohs(server_addr.sin_port);
printf("Server ip: %s, port: %d\n", server_ip, server_port);
printf("Server hostname: %.*s\n", 1021, &buffer[3]);
memset(buffer, 0, sizeof(buffer)); // 清空缓冲区
while(1) {
// 开始发送CMD_HELLO
buffer[0] = 24;
buffer[1] = CMD_HELLO;
buffer[2] = 0;
if (gethostname(&buffer[3], 1021) == -1) {
strcpy(&buffer[3], "Unknown Host");
}
ssize_t bytes_send = sendto(socketfd, buffer, 1024, 0, (struct sockaddr*)&server_addr, server_len);
if (bytes_send == -1) {
perror("Sending CMD_HELLO failed: \n");
continue;
} else {
break;
}
}
memset(buffer, 0, sizeof(buffer)); // 清空缓冲区
while(1) {
// 开始接收CMD_HELLOOK
ssize_t bytes_recv = recvfrom(socketfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&server_addr, &server_len);
if (bytes_recv == -1) {
perror("Receiving Data Failed: \n");
continue;
}
if (buffer[0] != 24 || buffer[1] != CMD_HELLOOK) {
printf("%d %d %d\n", buffer[0], buffer[1], buffer[2]);
printf("Is Not Allowed CMD_HELLOOK \n");
continue;
} else {
client_id = buffer[2];
printf("Client ID is %d\n", client_id);
break;
}
}
memset(buffer, 0, sizeof(buffer)); // 清空缓冲区
while(1) {
while(1) {
// 开始发送CMD_TASK
buffer[0] = 24;
buffer[1] = CMD_TASK;
buffer[2] = client_id;
ssize_t bytes_send = sendto(socketfd, buffer, 1024, 0, (struct sockaddr*)&server_addr, server_len);
if (bytes_send == -1) {
perror("Sending CMD_HELLO failed: \n");
continue;
} else {
break;
}
}
memset(buffer, 0, sizeof(buffer)); // 清空缓冲区
while(1) {
// 开始接收CMD_TASKOK
ssize_t bytes_recv = recvfrom(socketfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&server_addr, &server_len);
if (bytes_recv == -1) {
perror("Receive CMD_TASKOK Error: \n");
continue;
}
if (buffer[0] != 24 || buffer[1] != CMD_TASKOK || buffer[2] != client_id) {
printf("%d %d %d\n", buffer[0], buffer[1], buffer[2]);
printf("Is Not Allowed CMD_TASKOK \n");
continue;
} else {
break;
}
}
u_int32_t num1, num2;
memcpy(&num1, buffer + 3, sizeof(u_int32_t));
memcpy(&num2, buffer + 3 + sizeof(u_int32_t), sizeof(u_int32_t));
num1 = ntohl(num1);
num2 = ntohl(num2);
if (num1 == 0 && num2 == 0) // 两个数字都是0的话停止计算
{
break;
}
result = 0;
for(int i = num1; i <= num2; i++) {
if (is_prime(i) == 1) {
result = result + 1;
}
}
printf("Calc Finished: %u ~ %u = %u\n", num1, num2, result);
sleep(1); // todo 这块可以改 调节自己看得清的频率就行了
printf("Sleep Finished\n");
while(1) {
// 开始发送CMD_UPLOAD
buffer[1] = CMD_UPLOAD;
*((u_int32_t*)(buffer + 11)) = htonl(result);
ssize_t bytes_send = sendto(socketfd, buffer, 1024, 0, (struct sockaddr*)&server_addr, server_len);
if (bytes_send == -1) {
perror("Sending CMD_UPLOAD failed: \n");
continue;
} else {
break;
}
}
memset(buffer, 0, sizeof(buffer)); // 清空缓冲区
while(1) {
// 开始接收CMD_UPLOADOK
ssize_t bytes_recv = recvfrom(socketfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&server_addr, &server_len);
if (bytes_recv == -1) {
perror("Receive CMD_UPLOADOK Error: \n");
continue;
}
if (buffer[0] != 24 || buffer[1] != CMD_UPLOADOK || buffer[2] != client_id) {
printf("%d %d %d\n", buffer[0], buffer[1], buffer[2]);
printf("Is Not Allowed CMD_UPLOADOK \n");
continue;
} else {
break;
}
}
}
// 关闭套接字
close(socketfd);
return 0;
}
本文作者:御坂19327号
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!