原始套接字:接收器打印垃圾值
我想使用原始套接字使用发送器和接收器程序发送字符数组。我能够在接收端获得正确的字节数,但打印出的值是垃圾。有人可以帮我在这里吗?原始套接字:接收器打印垃圾值
发射机:
int create_raw_socket(char *dev)
{
struct sockaddr_ll sll;
struct ifreq ifr;
int fd, ifi, rb;
bzero(&sll, sizeof(sll));
bzero(&ifr, sizeof(ifr));
fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
assert(fd != -1);
strncpy((char *)ifr.ifr_name, dev, IFNAMSIZ);
ifi = ioctl(fd, SIOCGIFINDEX, &ifr);
assert(ifi != -1);
sll.sll_protocol = htons(ETH_P_ALL);
sll.sll_family = AF_PACKET;
sll.sll_ifindex = ifr.ifr_ifindex;
rb = bind(fd, (struct sockaddr *)&sll,sizeof(sll));
assert(rb != -1);
return fd;
}
int SendPacket(char *dev ,unsigned char *send_packet, int packet_len)
{
int num_sent= 0;
int sockaddress = create_raw_socket(dev);
if((num_sent = write(sockaddress, &send_packet, packet_len)) != packet_len)
{
close(sockaddress);
return 0;
}
else
{
close(sockaddress);
return 1;
}
}
int main(int argc, char**argv)
{
int x,fd,s;
char *send_packet="HELLO";
int len = sizeof(send_packet);
while(1)
{
if(!SendPacket((argv[1]), send_packet, len))
perror("Error sending packet");
else
printf("Packet sent successfully with payload : %s\n" ,send_packet);
}
return 0;
}
接收机:
int main(int argc, char **argv)
{
struct sockaddr addr;
int sock_fd, fromlen,s;
char buf[PACKET_LENGTH];
char *dev = argv[1];
while(1)
{
fromlen=sizeof(addr);
sock_fd = create_raw_socket(dev); /* Creating the raw socket */
int x= recvfrom(sock_fd,&buf,sizeof(buf),0,&addr,&fromlen);
printf("\n Number of bytes of data received is %d \n",x);
printf("\nPayload Received from client... is %s \n", buf);
close(sock_fd);
}
return 0;
}
变化
write(sockaddress, &send_packet, packet_len)
到
write(sockaddress, send_packet, packet_len)
send_packet
已经是缓冲区的地址发送,如果你把这个地址的地址(更准确地说是变量持有的地址地址),您将读取缓冲区的错误内存
同样对于recvfrom
:
recvfrom(sock_fd, buf, sizeof(buf), 0, &addr, &fromlen)
用printf打印缓冲器将打印一个字符串达到串字符的连接直到。如果您看到原始字符串后跟垃圾字符,则可能是原因。
您应该在recvfrom返回的最后一个字节之后引入一个0,否则您将打印recvfrom未覆盖的内存中的任何值。它甚至可以尝试访问缓冲区之外的内存。
尝试添加类似:
int x= recvfrom(sock_fd,&buf,sizeof(buf) - 1,0,&addr,&fromlen);
buf[x - 1] = 0;
注:改变的是什么读取的最大尺寸,它仅仅是如何做到这一点的例子。
你有几个问题:
-
此行
if((num_sent = write(sockaddress, &send_packet, packet_len)) != packet_len)
应该说的只是
send_packet
代替&send_packet
。send_packet
是一个指向所需数据包数据的指针,所以不需要使用它的地址 - 你不想将该指针的文字地址写入数据包,这根本就行不通。 -
这是错误的:
char *send_packet="HELLO"; int len = sizeof(send_packet);
sizeof(send_packet)
永远是你的系统,通常是4或8个字节上的指针的大小。您确实想要将send_packet
声明为阵列类型(例如char send_packet[] = ...
),或者使用strlen
来计算运行时的长度(例如int len = strlen(send_packet) + 1;
)。在你的情况下,你要么发送太少的数据(4字节)或太多的数据(8字节),这两者都是有问题的。 -
您的
printf
客户端的代码假定它收到的数据是空终止的,不一定是这样。您应该在打印数据之前手动对数据进行空终止处理(或者使用任何其他字符串函数),或者告诉打印多少数据的限制。我建议空的结束它像这样:char buf[PACKET_LENGTH + 1]; // +1 for null terminator int x = recvfrom(sock_fd,buf,PACKET_LENGTH,0,&addr,&fromlen); if(x >= 0) buf[x] = 0;
你的代码中有差
const
正确性。SendPacket
应取const char*
而不是char*
参数,并且send_packet
应宣布为char[]
或const char*
。从字符串文字到char*
的转换已被弃用,应该在所有新的C代码中避免。
感谢您指出了所有的问题。将在我的代码中纠正它。再次感谢。 – hektor
这对'write'调用是正确的,因为'send_packet'是一个指针,但对'recvfrom'的调用没有什么区别,因为'buf'是一个数组。数组类型具有这样的属性,即它们的地址在数值上等同于它们的第一个元素的地址,所以对于数组'x',总是这样:'(void *)&x ==(void *)&x [0]'。 –
谢谢@Attila和亚当,它像一个魅力:) – hektor