2024-03-04
大学课程
00

目录

1 修改后的客户端代码
2 修改后的服务端代码
3 运行效果
4 注意事项

实验目标:通过套接字和WSL,实现局域网内的通信。

1 修改后的客户端代码

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> int main(int argc, char const *argv[]) { printf("start sending message to server on 127.0.0.1:1324\n"); // 创建客户端套接字 int socketfd = socket(AF_INET, SOCK_DGRAM, 0); if (socketfd == -1) { perror("create socket failed: \n"); return -1; } // 创建服务器端地址 struct sockaddr_in server_addr; server_addr.sin_family = AF_INET; server_addr.sin_port = htons(1324); server_addr.sin_addr.s_addr = inet_addr("172.20.201.19"); // 开始发送数据 char* message = "Hello from client! \0"; ssize_t bytes_sent = sendto(socketfd, message, strlen(message), 0, (struct sockaddr*)&server_addr, sizeof(server_addr)); if (bytes_sent == -1) { perror("sending message failed: \n"); close(socketfd); return -1; } // 开始接收数据 char buffer[1024]; ssize_t bytes_recv = recvfrom(socketfd, buffer, sizeof(buffer), 0, NULL, NULL); if (bytes_recv == -1) { perror("receiving data failed: \n"); close(socketfd); return -1; } printf("received from server:\n"); printCharArrayToHex(buffer, 1024); // 关闭套接字 close(socketfd); return 0; } // 将char数组中的内容按十六进制进行打印 void printCharArrayToHex(char *buf, int bytes) { int i; for (i = 0; i < bytes; i++) { printf("%x ", (unsigned char)buf[i]); } }

2 修改后的服务端代码

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> // 创建一个简单UDP服务器 监听1324端口 int main(int argc, char const *argv[]) { printf("start monitor on 192.168.189.17:1324 \n"); // 创建套接字 int sockfd = socket(AF_INET, SOCK_DGRAM, 0); // SOCK_DGRAM是UDP套接字 // sockfd这个名字中的fd 是文件描述符的缩写 在unix/linux中 fd是进程独有的文件描述符表的索引 它的意思是 socket可以被视作一个文件 if (sockfd == -1) { perror("create socket failed: \n"); return -1; } // 设置服务器地址 struct sockaddr_in addr; addr.sin_family = AF_INET; // 地址族 addr.sin_port = htons(1324); // 端口 addr.sin_addr.s_addr = inet_addr("192.168.189.17"); // IP 另外 INADDR_ANY可表示0.0.0.0 // 将套接字绑定到服务器地址上 int ret = bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)); // addr这里 可以视作做了一个转型 if (0 > ret) { // 绑定失败 perror("bind failed: \n"); close(sockfd); return -1; } // 设置客户端地址 struct sockaddr_in client_addr; socklen_t client_len = sizeof(client_addr); char buffer[1024]; while (1) { ssize_t bytes_recv = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&client_addr, &client_len); if (bytes_recv == -1) { perror("receive message error: \n"); continue; } 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("received from client: %s\n", buffer); memset(buffer, 0, sizeof(buffer)); // 按老师要求 编写自定义回复内容 const char* response = "Hello from server! \0"; // 定义char数组 char buf[1024]; // 声明一个指针 并且指向buf数组的第一个元素 u_int8_t *p; p = buf; // 填充24进去 buf[0] = 24; // 指针转型 使得编辑的内容从一位变成了两位 另外多字节内容必须转换字节序 *((u_int16_t*)(buf + 1)) = htons(2024); // 同上的指针转型 *((u_int32_t*)(buf + 3)) = htonl(20240304); // 获取主机名 如果无法获取则填充"Unknown Host" if (gethostname(buf + 7, 1017) == -1) { strcpy(buf + 7, "Unknown Host"); } ssize_t bytes_send = sendto(sockfd, buf, 1017, 0, (struct sockaddr*)&client_addr, client_len); if (bytes_send == -1) { perror("sending message error: \n"); } } close(sockfd); return 0; }

3 运行效果

image.png

image.png

可见局域网内的两个IP成功地进行通信,并且通信内容中包含主机名。

4 注意事项

  1. 局域网内的两个主机通过这种方式通信,必须关闭双方主机的防火墙:

    image.png

  2. 如果WSL想要被外界以一个固定IP访问,那么必须修改用户文件夹下的.wslconfig文件,并且修改hostAddressLoopback参数为true

    image.png

    在这里附上微软官方的说明:

    image.png

    (请注意,该说明为2024年3月5日截取,实际微软可能修改,请以最新说明为准WSL中的高级设置配置 | Microsoft Learn

    实际效果:

    image.png

本文作者:御坂19327号

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!