域套接字 Unix domain socket
Unix Domain Socket(UDS,Unix 域套接字),它还有另一个名字叫 IPC(inter-process communication,进程间通信)。
使用 UDS 的好处显而易见:不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程。这是因为,IPC 机制本质上是可靠的通讯,而网络协议是为不可靠的通讯设计的。
UDS 与网络 Socket 最明显的区别在于,网络 Socket 地址是 IP 地址加端口号,而 UDS 的地址是一个 Socket 类型的文件在文件系统中的路径,一般名字以 .sock 结尾。
特点:
只能用于同一设备上不同进程之间的通信;
效率高于网络套接字。域套接字仅仅是复制数据,并不走协议栈;
可靠,全双工;
域套接字地址结构:
struct sockaddr_un {
sa_family_t sun_family; /*AF_UNIX*/
char sun_path[108]; /*pathname*/
};
当我们将一个地址绑定至域套接字,系统用该路径名创建一个类型为S_IFSOCK的文件,尽告诉客户端名字,不能打开,也不能通信,不会自动删除,需要程序完成后删除,若文件已存在则bind失败;
测试代码
server.c
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#define UN_PATH "/var/tmp/test_domain_socket"
int main(int argc, char *argv[])
{
int sockfd = -1;
struct sockaddr_un un;
int len = 0;
if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
perror("create socket error\n");
goto _ERROR;
}
memset(&un, 0, sizeof(un));
un.sun_family = AF_UNIX;
strcpy(un.sun_path, UN_PATH);
len = sizeof(un.sun_family) + sizeof(un.sun_path);
if (bind(sockfd, (struct sockaddr *)&un, len) < 0){
perror("socket bind error\n");
goto _ERROR;
}
if (listen(sockfd, 5) < 0){
perror("socket listen error\n");
}
int conn = accept(sockfd, (struct sockaddr *)&un, &len);
if (conn < 0){
perror("accept error\n");
goto _ERROR;
}
char buf[64] = {0};
int n = read(conn, buf, 63);
printf("recive-msg:%s", buf);
write(conn, buf, n);
close(conn);
close(sockfd);
unlink(UN_PATH);
return 0;
_ERROR:
if (sockfd != -1){
close(sockfd);
}
return -1;
}
client.c
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define UN_PATH "/var/tmp/test_domain_socket"
int main(int argc, char *argv[])
{
int sockfd = -1;
struct sockaddr_un un;
int len = 0;
if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
perror("create socket error\n");
goto _ERROR;
}
memset(&un, 0, sizeof(un));
un.sun_family = AF_UNIX;
strcpy(un.sun_path, UN_PATH);
len = sizeof(un.sun_family) + sizeof(un.sun_path);
if (connect(sockfd, (struct sockaddr *)&un, len) < 0){
perror("socket connect error\n");
goto _ERROR;
}
char buf[64] = {0};
int n = read(STDIN_FILENO, buf, 63);
write(sockfd, buf, n);
printf("send-msg:%s", buf);
read(sockfd, buf, 63);
buf[64] = '\0';
printf("recv-msg:%s", buf);
close(sockfd);
return 0;
_ERROR:
if (sockfd != -1){
close(sockfd);
}
return -1;
}
原始套接字 raw socket
即原始套接字,可以接收本机网卡上的数据帧或者数据包,对于监听网络的流量和分析是很有作用的,一共可以有4种方式创建这种socket。
socket(PF_INET, SOCK_RAW, IPPROTO_TCP|IPPROTO_UDP|IPPROTO_ICMP) // 发送接收ip数据包
socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL)) // 发送接收以太网数据帧
socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL)) // 发送接收以太网数据帧(不包括以太网头部) [1]
socket(PF_INET, SOCK_PACKET, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL)) // 过时了,不要用啊
RGMII以太网测试方案
二 实现步骤
1.模组的MAC通过RGMII接口与PHY连接
2.MAC层数据经过RGMII到达PHY的PCS层
3.设置PHY的PCS层回环,使PCS层数据回到MAC层
4.判断MAC层TX与RX接收的数据。如果MAC能接收到数据,测试PASS,否则失败
测试代码
int main(int argc, char **argv)
{
int i, datalen, frame_length, sd, bytes;
char *interface = "eth0";
uint8_t data[IP_MAXPACKET];
uint8_t src_mac[6];
uint8_t dst_mac[6];
uint8_t ether_frame[IP_MAXPACKET];
struct sockaddr_ll device;
struct ifreq ifr;
int recvlen=0;
uint8_t buffer[IP_MAXPACKET];
int loopback_state=0;
// Submit request for a socket descriptor to look up interface.
if ((sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0)
{
perror("socket() failed to get socket descriptor for using ioctl()");
exit(EXIT_FAILURE);
}
// Use ioctl() to look up interface name and get its MAC address.
memset(&ifr, 0, sizeof(ifr));
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", interface);
if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
{
perror("ioctl() failed to get source MAC address ");
return (EXIT_FAILURE);
}
close(sd);
// Copy source MAC address.
memcpy(src_mac, ifr.ifr_hwaddr.sa_data, 6);
// Report source MAC address to stdout.
printf("MAC address for interface %s is ", interface);
for (i = 0; i < 5; i++)
{
printf("%02x:", src_mac[i]);
}
printf("%02x\n", src_mac[5]);
// Find interface index from interface name and store index in
// struct sockaddr_ll device, which will be used as an argument of sendto().
memset(&device, 0, sizeof(device));
if ((device.sll_ifindex = if_nametoindex(interface)) == 0)
{
perror("if_nametoindex() failed to obtain interface index ");
exit(EXIT_FAILURE);
}
printf("Index for interface %s is %i\n", interface, device.sll_ifindex);
// Set destination MAC address: you need to fill these out
dst_mac[0] = 0x10; //设置目的网卡地址
dst_mac[1] = 0x78;
dst_mac[2] = 0xd2;
dst_mac[3] = 0xc6;
dst_mac[4] = 0x2f;
dst_mac[5] = 0x89;
// Fill out sockaddr_ll.
device.sll_family = AF_PACKET;
memcpy(device.sll_addr, src_mac, 6);
device.sll_halen = htons(6);
// 发送的data,长度可以任意,但是抓包时看到最小数据长度为46,这是以太网协议规定以太网帧数据域部分最小为46字节,不足的自动补零处理
datalen = 12;
data[0] = 0x11;
data[1] = 0x12;
data[2] = 0x13;
data[3] = 0x14;
data[4] = 0x15;
data[5] = 0x16;
data[6] = 0x17;
data[7] = 0x18;
data[8] = 0x19;
data[9] = 0x20;
data[10] = 0x21;
data[11] = 0x22;
// Fill out ethernet frame header.
frame_length = 6 + 6 + 2 + datalen;
// Destination and Source MAC addresses
memcpy(ether_frame, dst_mac, 6);
memcpy(ether_frame + 6, src_mac, 6);
ether_frame[12] = ETH_P_DEAN / 256;
ether_frame[13] = ETH_P_DEAN % 256;
// data
memcpy(ether_frame + 14, data, datalen);
// Submit request for a raw socket descriptor.
if ((sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0)
{ //创建正真发送的socket
perror("socket() failed ");
exit(EXIT_FAILURE);
}
// Send ethernet frame to socket.
if ((bytes = sendto(sd, ether_frame, frame_length, 0, (struct sockaddr *)&device, sizeof(device))) <= 0)
{
perror("sendto() failed");
exit(EXIT_FAILURE);
}
for(i=0;i<bytes;i++){
printf(" %02x",ether_frame[i]);
if((i+1)%16==0){
printf("\n");
}
}
printf("\n");
recvlen=recvfrom(sd,buffer,sizeof(buffer),0,NULL,NULL);
for(i=0;i<recvlen;i++){
printf(" %02x",buffer[i]);
if((i+1)%16==0){
printf("\n");
}
}
printf("\n");
for(i=0;i<recvlen;i++){
if(bytes>recvlen)
{
loopback_state=0;
break;
}
else if(ether_frame[i]!=buffer[i])
{
loopback_state=0;
break;
}
}
if (loopback_state == 1)
{
printf("phy loopback OK\n");
}
else
{
printf("phy loopback error\n");
}
// Close socket descriptor.
close(sd);
return (EXIT_SUCCESS);
}
https://blog.csdn.net/gtychuashuiwang/article/details/127210729
https://blog.csdn.net/baidu_19348579/article/details/121143202