网络部分阶段测试编程题
This commit is contained in:
parent
5cdb1cc311
commit
93ec33f5b6
Binary file not shown.
|
@ -0,0 +1,62 @@
|
||||||
|
// 利用 setsocketopt() 使用嵌套字支持广播,并编写两个程序,其中一个发送广播数据,另一个接收广播数据
|
||||||
|
// 客户端
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
int main(int argc, char const *argv[])
|
||||||
|
{
|
||||||
|
int sockfd = socket(AF_INET, SOCK_DGRAM, 0); // 创建UDP套接字
|
||||||
|
if (sockfd < 0)
|
||||||
|
{
|
||||||
|
perror("socket error");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_in broadcast_addr, recv_addr; // 广播地址信息结构体对象, 接收广播消息的地址信息结构体对象
|
||||||
|
memset(&recv_addr, 0, sizeof(recv_addr)); // 初始化接收广播消息的地址信息结构体对象
|
||||||
|
recv_addr.sin_family = AF_INET; // 设置地址族
|
||||||
|
recv_addr.sin_port = htons(8000); // 设置端口号
|
||||||
|
recv_addr.sin_addr.s_addr = INADDR_ANY; // 设置接收任意地址
|
||||||
|
|
||||||
|
// 绑定套接字
|
||||||
|
int is_bind = bind(sockfd, (struct sockaddr *)&recv_addr, sizeof(recv_addr)); // 绑定套接字
|
||||||
|
if (is_bind < 0)
|
||||||
|
{
|
||||||
|
perror("bind error");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置套接字选项,启用地址重用,允许接收广播消息
|
||||||
|
int reuse_flag = 1;
|
||||||
|
// 说明:SOL_SOCKET表示当前套接字,SO_REUSEADDR表示启用地址重用,&reuse_flag表示设置选项的值,sizeof(flag)表示选项值的大小
|
||||||
|
int ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse_flag, sizeof(reuse_flag));
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
perror("setsockopt error");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 接收广播消息
|
||||||
|
char recv_buf[1024]; // 接收缓冲区
|
||||||
|
|
||||||
|
// 参数说明: sockfd表示套接字描述符,recv_buf表示接收缓冲区,sizeof(recv_buf)表示接收缓冲区大小,0表示阻塞接收,NULL表示不关注对端地址信息,0表示不关注对端地址信息长度
|
||||||
|
ssize_t recv_len = recvfrom(sockfd, recv_buf, sizeof(recv_buf), 0, NULL, 0);
|
||||||
|
if (recv_len < 0)
|
||||||
|
{
|
||||||
|
perror("recvfrom error");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("接收到广播消息: %s\n", recv_buf);
|
||||||
|
|
||||||
|
// 关闭套接字
|
||||||
|
close(sockfd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Binary file not shown.
|
@ -0,0 +1,50 @@
|
||||||
|
// 利用 setsocketopt() 使用嵌套字支持广播,并编写两个程序,其中一个发送广播数据,另一个接收广播数据
|
||||||
|
// 服务端
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
int main(int argc, char const *argv[])
|
||||||
|
{
|
||||||
|
int sockfd = socket(AF_INET, SOCK_DGRAM, 0); // 创建UDP套接字
|
||||||
|
if (sockfd < 0)
|
||||||
|
{
|
||||||
|
perror("socket error");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
char broadcast_msg[] = "this is a udp broadcast message"; // 广播消息
|
||||||
|
|
||||||
|
// 构造广播地址信息结构体对象
|
||||||
|
struct sockaddr_in broadcast_addr; // 广播地址信息结构体对象
|
||||||
|
memset(&broadcast_addr, 0, sizeof(broadcast_addr)); // 初始化广播地址信息结构体对象
|
||||||
|
broadcast_addr.sin_family = AF_INET; // 设置地址族
|
||||||
|
broadcast_addr.sin_port = htons(8000); // 设置端口号
|
||||||
|
broadcast_addr.sin_addr.s_addr = inet_addr("255.255.255.255"); // 设置广播地址
|
||||||
|
|
||||||
|
// 设置套接字选项,允许发送广播消息
|
||||||
|
int broadcast_enable_flag = 1;
|
||||||
|
// 说明:SOL_SOCKET表示当前套接字,SO_BROADCAST表示允许发送广播消息,&broadcast_enable_flag表示设置选项的值,sizeof(flag)表示选项值的大小
|
||||||
|
int ret = setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcast_enable_flag, sizeof(broadcast_enable_flag));
|
||||||
|
|
||||||
|
// 发送广播消息
|
||||||
|
ssize_t send_len = sendto(sockfd, broadcast_msg, strlen(broadcast_msg), 0, (struct sockaddr *)&broadcast_addr, sizeof(broadcast_addr));
|
||||||
|
if (send_len < 0)
|
||||||
|
{
|
||||||
|
perror("sendto error");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("广播消息发送成功 (%s)\n", broadcast_msg);
|
||||||
|
|
||||||
|
// 关闭套接字
|
||||||
|
close(sockfd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
// 写一个 TCP 并发的服务器,实现 echo 功能
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
int main(int argc, char const *argv[])
|
||||||
|
{
|
||||||
|
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (sockfd < 0)
|
||||||
|
{
|
||||||
|
perror("socket");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_in server_addr;
|
||||||
|
memset(&server_addr, 0, sizeof(server_addr));
|
||||||
|
server_addr.sin_family = AF_INET; // ipv4
|
||||||
|
server_addr.sin_port = htons(8000); // port
|
||||||
|
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 服务端的ip地址 : 默认接收任意ip地址的连接
|
||||||
|
|
||||||
|
if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0)
|
||||||
|
{
|
||||||
|
perror("bind");
|
||||||
|
close(sockfd); // 关闭 socket 套接字描述符
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
listen(sockfd, 5); // 创建队列长度为5的监听队列
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
struct sockaddr_in client_addr; // 客户端地址信息
|
||||||
|
memset(&client_addr, 0, sizeof(client_addr));
|
||||||
|
socklen_t client_addr_len = sizeof(client_addr); // 地址信息长度
|
||||||
|
|
||||||
|
int client_fd = accept(sockfd, (struct sockaddr *)&client_addr, &client_addr_len); // 从监听队列中取出一个连接
|
||||||
|
if (client_fd < 0)
|
||||||
|
{
|
||||||
|
perror("accept");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
char client_ip[INET_ADDRSTRLEN] = ""; // 用于保存客户端的ip地址
|
||||||
|
inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, sizeof(client_ip)); // 将网络字节序的ip地址转换为点分十进制的ip地址
|
||||||
|
printf("客户端 %s 连接成功\n", client_ip);
|
||||||
|
|
||||||
|
pid_t pid = fork(); // 创建子进程
|
||||||
|
if (pid == 0)
|
||||||
|
{
|
||||||
|
close(sockfd); // 关闭子进程中的监听套接字描述符
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
char buf[128] = "";
|
||||||
|
ssize_t recv_len = recv(client_fd, buf, sizeof(buf), 0); // 接收客户端发送的数据
|
||||||
|
if (recv_len > 0)
|
||||||
|
{
|
||||||
|
char send_buf[1024] = "";
|
||||||
|
sprintf(send_buf, "收到 %s 发送的数据: %s", client_ip, buf);
|
||||||
|
|
||||||
|
send(client_fd, send_buf, strlen(send_buf), 0); // 发送数据给客户端
|
||||||
|
|
||||||
|
if (strncmp(buf, "exit", 4) == 0)
|
||||||
|
{
|
||||||
|
printf("客户端 %s 断开连接\n", client_ip);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close(client_fd); // 关闭客户端连接套接字描述符
|
||||||
|
printf("客户端 %s 断开连接\n", client_ip);
|
||||||
|
exit(0); // 子进程退出
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close(sockfd); // 关闭监听套接字描述符
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,132 @@
|
||||||
|
/*
|
||||||
|
* 写一个网络数据分析器
|
||||||
|
* 要求:
|
||||||
|
* 1、对 arp/ip/tcp/udp 数据进行区分。
|
||||||
|
* 2、把数据包中的源信息,目的信息等重要的信息打印出来。
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <pcap/pcap.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <string.h> // memset
|
||||||
|
#include <net/ethernet.h> // ether_header
|
||||||
|
#include <netinet/ip.h> // ip
|
||||||
|
#include <netinet/if_ether.h> // ether_arp
|
||||||
|
#include <unistd.h> // sleep
|
||||||
|
|
||||||
|
int main(int argc, char const *argv[])
|
||||||
|
{
|
||||||
|
char errbuf[PCAP_ERRBUF_SIZE]; // 用于存储错误信息的缓冲区
|
||||||
|
char *dev = pcap_lookupdev(errbuf); // 获取网络接口
|
||||||
|
if (dev == NULL) // 获取网络接口失败
|
||||||
|
{
|
||||||
|
printf("pcap_lookupdev error: %s\n", errbuf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
printf("网络接口: %s\n", dev);
|
||||||
|
|
||||||
|
// 获取网卡的网络号,掩码地址
|
||||||
|
bpf_u_int32 netip, netmask;
|
||||||
|
if (pcap_lookupnet(dev, &netip, &netmask, NULL) == 0)
|
||||||
|
{
|
||||||
|
unsigned char ip[INET_ADDRSTRLEN] = "";
|
||||||
|
unsigned char mask[INET_ADDRSTRLEN] = "";
|
||||||
|
|
||||||
|
inet_ntop(AF_INET, &netip, ip, INET_ADDRSTRLEN);
|
||||||
|
inet_ntop(AF_INET, &netmask, mask, INET_ADDRSTRLEN);
|
||||||
|
printf("网络地址: %s 掩码地址: %s\n", ip, mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开网络设备,开始捕获数据
|
||||||
|
pcap_t *pcap_handle = pcap_open_live(dev, BUFSIZ, 1, 0, errbuf);
|
||||||
|
if (pcap_handle == NULL)
|
||||||
|
{
|
||||||
|
printf("pcap_open_live error: %s\n", errbuf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
struct pcap_pkthdr pcap_hdr; // 数据包头
|
||||||
|
memset(&pcap_hdr, 0, sizeof(pcap_hdr)); // 清空结构体
|
||||||
|
const u_char *packet = pcap_next(pcap_handle, &pcap_hdr); // 获取数据包
|
||||||
|
if (packet == NULL)
|
||||||
|
{
|
||||||
|
printf("pcap_next error\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分析 ethernet 报文类型
|
||||||
|
// 如果是 arp 报文,则打印 arp 报文信息
|
||||||
|
// 如果是 ip 报文,则打印 ip 报文信息
|
||||||
|
struct ether_header *eth_hdr = (struct ether_header *)packet;
|
||||||
|
// 拆分源 mac 地址和目的 mac 地址
|
||||||
|
unsigned char src_mac_x[ETHER_ADDR_LEN] = ""; // 源 mac 地址
|
||||||
|
unsigned char dst_mac_x[ETHER_ADDR_LEN] = ""; // 目的 mac 地址
|
||||||
|
memcpy(src_mac_x, eth_hdr->ether_shost, ETHER_ADDR_LEN); // 拷贝源 mac 地址
|
||||||
|
memcpy(dst_mac_x, eth_hdr->ether_dhost, ETHER_ADDR_LEN); // 拷贝目的 mac 地址
|
||||||
|
|
||||||
|
char src_mac[18] = ""; // 存储 MAC 地址的字符串
|
||||||
|
char dst_mac[18] = ""; // 存储 MAC 地址的字符串
|
||||||
|
|
||||||
|
// 将 MAC 地址转换成字符串
|
||||||
|
sprintf(src_mac, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||||
|
src_mac_x[0], src_mac_x[1], src_mac_x[2], src_mac_x[3], src_mac_x[4], src_mac_x[5]);
|
||||||
|
|
||||||
|
sprintf(dst_mac, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||||
|
dst_mac_x[0], dst_mac_x[1], dst_mac_x[2], dst_mac_x[3], dst_mac_x[4], dst_mac_x[5]);
|
||||||
|
|
||||||
|
if (ntohs(eth_hdr->ether_type) == ETHERTYPE_ARP)
|
||||||
|
{
|
||||||
|
// 拆分源 ip 地址和目的 ip 地址
|
||||||
|
unsigned char src_ip[INET_ADDRSTRLEN] = ""; // 源 ip 地址
|
||||||
|
unsigned char dst_ip[INET_ADDRSTRLEN] = ""; // 目的 ip 地址
|
||||||
|
struct ether_arp *arp_hdr = (struct ether_arp *)(packet + sizeof(struct ether_header));
|
||||||
|
inet_ntop(AF_INET, arp_hdr->arp_spa, src_ip, INET_ADDRSTRLEN); // 拷贝源 ip 地址
|
||||||
|
inet_ntop(AF_INET, arp_hdr->arp_tpa, dst_ip, INET_ADDRSTRLEN); // 拷贝目的 ip 地址
|
||||||
|
|
||||||
|
printf("arp 报文\n");
|
||||||
|
printf("源地址: %s\t\t目的地址: %s\n源MAC: %s\t目的MAC: %s\n", src_ip, dst_ip, src_mac, dst_mac); // 打印 arp 报文信息
|
||||||
|
}
|
||||||
|
else if (ntohs(eth_hdr->ether_type) == ETHERTYPE_IP)
|
||||||
|
{
|
||||||
|
// 拆分源 ip 地址和目的 ip 地址
|
||||||
|
unsigned char src_ip[INET_ADDRSTRLEN] = ""; // 源 ip 地址
|
||||||
|
unsigned char dst_ip[INET_ADDRSTRLEN] = ""; // 目的 ip 地址
|
||||||
|
struct ip *ip_hdr = (struct ip *)(packet + sizeof(struct ether_header));
|
||||||
|
inet_ntop(AF_INET, &ip_hdr->ip_src, src_ip, INET_ADDRSTRLEN); // 拷贝源 ip 地址
|
||||||
|
inet_ntop(AF_INET, &ip_hdr->ip_dst, dst_ip, INET_ADDRSTRLEN); // 拷贝目的 ip 地址
|
||||||
|
|
||||||
|
printf("ip 报文\n");
|
||||||
|
|
||||||
|
// 分析 ip 报文类型
|
||||||
|
// 如果是 tcp 报文,则打印 tcp 报文信息
|
||||||
|
// 如果是 udp 报文,则打印 udp 报文信息
|
||||||
|
if (ip_hdr->ip_p == IPPROTO_TCP)
|
||||||
|
{
|
||||||
|
printf("tcp 报文\n");
|
||||||
|
printf("源地址: %s\t\t目的地址: %s\n源MAC: %s\t目的MAC: %s\n", src_ip, dst_ip, src_mac, dst_mac); // 打印 ip 报文信息
|
||||||
|
}
|
||||||
|
else if (ip_hdr->ip_p == IPPROTO_UDP)
|
||||||
|
{
|
||||||
|
printf("udp 报文\n");
|
||||||
|
printf("源地址: %s\t\t目的地址: %s\n源MAC: %s\t目的MAC: %s\n", src_ip, dst_ip, src_mac, dst_mac); // 打印 ip 报文信息
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("其他报文\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("其他报文\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭网络设备
|
||||||
|
pcap_close(pcap_handle);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue