我正在编写原始套接字客户端(成功发送UDP数据包)和服务器套接字,问题出在服务器部分。
我用以下方式创建套接字:
int raw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
我也尝试使用IPPROTO_RAW,但得到相同的结果并且我绑定它:
bind(raw_socket, (struct sockaddr*)&sockstr, sizeof(sockstr))
当尝试使用套接字接收一些数据包时,我收到的唯一有效负载是" E" (我认为这意味着"错误"),或者套接字继续监听但阻止并且没有任何反应。 如何使用原始套接字接收UDP数据包? 我的代码:
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
int server(){
int raw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
if (raw_socket== -1){
perror("Socket_creation_error\n");
return 1;
}
struct sockaddr_in sockstr;
sockstr.sin_addr.s_addr = inet_addr("127.0.0.1");
sockstr.sin_family = AF_INET;
sockstr.sin_port = htons(9090);
socklen_t s = (socklen_t)sizeof(sockstr);
if (bind(raw_socket, (struct sockaddr*)&sockstr, sizeof(sockstr))< 0){
perror("binding_err\n");
return 0;
}
char* msg[256];
memset(msg, 0, 256);
recv(raw_socket, msg, sizeof(msg), 0);
printf(msg);
return 0;
}
void main(){
server();
}
答案 0 :(得分:2)
正如原始套接字手册所说user@host:~$ man 7 raw
:
IPPROTO_RAW协议意味着启用了IP_HDRINCL,能够发送在传递的标头中指定的任何IP协议。 使用原始套接字无法通过IPPROTO_RAW接收所有IP协议。
从手册中提取的另一个重要说明是:
只允许有效用户ID为0或CAP_NET_RAW功能的进程打开原始套接字。
手册也说:
从Linux 2.2开始,可以使用IP套接字选项设置所有IP标头字段和选项。这意味着原始套接字通常仅用于没有用户界面的新协议或协议(如ICMP)。
好的,假设您需要手头有IP / UPD标题,让我们去上班:-)
首先,我们需要澄清一些观点:
#include ...
标题。char *msg[SIZE]
???这是一个char指针数组!您只需要一组字符,例如:char msg[SIZE]
。#include <linux/ip.h>
和#include <linux/udp.h>
以获取标题的大小。)的main.c
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <linux/ip.h> /* for ipv4 header */
#include <linux/udp.h> /* for upd header */
#define ADDR_TO_BIND "127.0.0.1"
#define PORT_TO_BIND 9090
#define MSG_SIZE 256
#define HEADER_SIZE (sizeof(struct iphdr) + sizeof(struct udphdr))
int main(void) {
int raw_socket;
struct sockaddr_in sockstr;
socklen_t socklen;
int retval = 0; /* the return value (give a look when an error happens)
*/
/* no pointer to array!
* >> It was like "a variable that contains an address -- and in this
* address begins an array of chars"! */
/* now it is simple an array of chars :-) */
char msg[MSG_SIZE];
ssize_t msglen; /* return value from recv() */
/* do not use IPPROTO_RAW to receive packets */
if ((raw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_UDP)) == -1) {
perror("socket");
return 1; /* here there is no clean up -- retval was not used */
}
sockstr.sin_family = AF_INET;
sockstr.sin_port = htons(PORT_TO_BIND);
sockstr.sin_addr.s_addr = inet_addr(ADDR_TO_BIND);
socklen = (socklen_t) sizeof(sockstr);
/* use socklen instead sizeof() Why had you defined socklen? :-) */
if (bind(raw_socket, (struct sockaddr*) &sockstr, socklen) == -1) {
perror("bind");
retval = 1; /* '1' means "Error" */
goto _go_close_socket;
}
memset(msg, 0, MSG_SIZE);
if ((msglen = recv(raw_socket, msg, MSG_SIZE, 0)) == -1) {
perror("recv");
retval = 1;
goto _go_close_socket;
}
if (msglen <= HEADER_SIZE) /* msg can't be lesser than header! */
printf("No msg!\n");
else {
msg[msglen - 1] = '\0'; /* we need a null character at the end*/
printf("Your msg _plus_ headers's size is: %s\n",
msg + HEADER_SIZE);
}
_go_close_socket:
close(raw_socket);
return retval;
}
好的,现在编译程序:
user@host:~$ gcc -o main main.c
以root身份执行:
root@host:~# ./main
在另一个终端中发送带有 nc 的消息:
-u 指定UPD到 nc
user@host:~$ nc -u 127.0.0.1 9090
就是这样!