我正在编写原始套接字客户端(成功发送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();
}发布于 2016-11-27 03:11:30
正如原始套接字手册所说的那样,user@host:~$ man 7 raw
IPPROTO_RAW的协议表示启用了IP_HDRINCL,并且能够向发送passed报头中指定的任何IP协议。无法使用原始套接字通过IPPROTO_RAW接收所有IP协议。
从手册中摘录的另一个重要说明是:
仅允许有效用户ID为0或具有CAP_NET_RAW功能的进程打开原始套接字。
手册上也写道:
从Linux2.2开始,所有IP报头字段和选项都可以使用IP套接字选项进行设置。这意味着通常只有新协议或没有用户界面的协议(如ICMP)才需要原始套接字。
好的,假设您需要准备好IP/UPD标头,让我们开始工作:-)
首先,我们需要明确几点:
在上面的代码中,一些socklen头是missing.
#include ...?例如,你可以在bind().char *msg[SIZE]中使用它,它是一个字符指针数组!您只需要一个字符数组,如下所示:char msg[SIZE].#include <linux/ip.h>和#include <linux/udp.h>来获取标头的size).#include <linux/ip.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指定更新到nc
user@host:~$ nc -u 127.0.0.1 9090
就是这样!
https://stackoverflow.com/questions/40795772
复制相似问题