我的客户端 - 服务器C程序出现问题。
该计划有两个主要部分。在第一部分中,消息通过多播从内核模块发送到用户空间侦听器。我已多次尝试并测试了该程序的这一部分,并且按预期工作。
程序的第二部分将收到的消息传送到另一台机器(机器2)。因此,来自Machine 1的Userspace侦听器从内核获取消息,然后充当客户端,在机器1和机器2之间打开一个套接字。机器2中的服务器接收消息并将其打印到stdout。然后它等待另一条消息。
问题似乎是recvmsg()函数第一次阻塞但在后续迭代中没有阻塞。就好像套接字中的信息一直存在,因此阻止了recvmsg()阻塞。结果是同一条信息在循环中传输。
我在这个recvmsg()问题上错了。也许有人有更多的经验,可以指出我正确的方向。代码和输出如下。非常感谢。
NetLinkUser_Client.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <unistd.h>
#include <errno.h>
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#define MAX_PAYLOAD 1024
#define MY_GROUP 1
#define OUT_PORT "5001"
#define OUT_IP "192.168.xxx.xxx"
void client(char *msg) {
int socketfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
portno = atoi(OUT_PORT);
/* Create a socket point */
socketfd = socket(AF_INET, SOCK_STREAM, 0);
if (socketfd < 0) {
perror("ERROR opening socket");
exit(1);
}
server = gethostbyname(OUT_IP);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
serv_addr.sin_port = htons(portno);
/* Now connect to the server */
if (connect(socketfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
perror("ERROR connecting");
exit(1);
}
/* Now send a message to the server, this message
* will be read by server
*/
char buffer[MAX_PAYLOAD];
bzero(buffer,MAX_PAYLOAD);
strcpy(buffer, msg);
printf("\nThe contents of the buffer is: %s\n", buffer);
printf("\nThe length of the buffer is: %d\n", strlen(buffer));
/* Send message to the server */
n = write(socketfd, buffer, strlen(buffer));
if (n < 0) {
perror("ERROR writing to socket");
exit(1);
}
bzero(buffer,MAX_PAYLOAD);
printf("%s\n",buffer);
close(socketfd);
}
int main(void)
{
int sock_fd;
struct sockaddr_nl user_sockaddr;
struct nlmsghdr *nl_msghdr;
struct msghdr msghdr;
struct iovec iov;
char* kernel_msg;
sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_USERSOCK);
if(sock_fd<0)
{
printf("Error creating socket because: %s\n", strerror(errno));
return -1;
}
memset(&user_sockaddr, 0, sizeof(user_sockaddr));
user_sockaddr.nl_family = AF_NETLINK;
user_sockaddr.nl_pid = getpid();
user_sockaddr.nl_groups = MY_GROUP;
bind(sock_fd, (struct sockaddr*)&user_sockaddr, sizeof(user_sockaddr));
while (1) {
ssize_t recvmsg_err = 0;
nl_msghdr = (struct nlmsghdr*) malloc(NLMSG_SPACE(1024));
memset(nl_msghdr, 0, NLMSG_SPACE(1024));
// The issue is not related to zeroing out msghdr
printf("The struct member msghdr.msg_namelen has the value : %d before zeroing out\n", msghdr.msg_namelen);
memset(&msghdr, 0, sizeof(msghdr));
printf("The struct member msghdr.msg_namelen has the value : %d after zeroing out\n", msghdr.msg_namelen);
memset(&iov, 0, sizeof(iov));
iov.iov_base = (void*) nl_msghdr;
iov.iov_len = NLMSG_SPACE(1024);
msghdr.msg_name = (void*) &user_sockaddr;
msghdr.msg_namelen = sizeof(user_sockaddr);
msghdr.msg_iov = &iov;
msghdr.msg_iovlen = 1;
printf("The struct member msghdr.msg_namelen has the value : %d after initialization\n", msghdr.msg_namelen);
printf("Waiting to receive message\n");
// Execution not pausing here WHY??
printf("recvmsg() should wait here\n");
recvmsg_err = recvmsg(sock_fd, &msghdr, 0);
if(recvmsg_err == -1)
{
perror("Error in recvmsg\n");
}
printf("The value returned by recvmsg() is %d\n", recvmsg_err);
kernel_msg = (char*)NLMSG_DATA(nl_msghdr);
printf("Kernel message: %s\n", kernel_msg); // print to android logs
client(kernel_msg);
}
close(sock_fd);
}
MsgServer.c
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
#define MAX_PAYLOAD 1024
void doprocessing (int sock) {
int n;
char buffer[MAX_PAYLOAD];
bzero(buffer,MAX_PAYLOAD);
n = read(sock,buffer,MAX_PAYLOAD);
if (n < 0) {
perror("ERROR reading from socket");
exit(1);
}
printf("The length of the buffer is %d\n", strlen(buffer));
printf("Here is the message: %s\n",buffer);
}
int main( int argc, char *argv[] ) {
int sockfd, newsockfd, portno, clilen;
char buffer[1024];
struct sockaddr_in serv_addr, cli_addr;
int n, pid;
/* First call to socket() function */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("ERROR opening socket");
exit(1);
}
/* Initialize socket structure */
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = 5001;
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
/* Now bind the host address using bind() call.*/
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
perror("ERROR on binding");
exit(1);
}
/* Now start listening for the clients, here
* process will go in sleep mode and will wait
* for the incoming connection
*/
listen(sockfd,5);
clilen = sizeof(cli_addr);
while (1) {
printf("Waiting for initial connection in doProcessing() while loop\n");
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0) {
perror("ERROR on accept");
exit(1);
}
/* Create child process */
pid = fork();
if (pid < 0) {
perror("ERROR on fork");
exit(1);
}
if (pid == 0) {
/* This is the client process */
close(sockfd);
doprocessing(newsockfd);
exit(0);
}
else {
close(newsockfd);
}
} /* end of while */
}
客户端示例输出
The struct member msghdr.msg_namelen has the value : 12 before zeroing out
The struct member msghdr.msg_namelen has the value : 0 after zeroing out
The struct member msghdr.msg_namelen has the value : 12 after initialization
Waiting to receive message
recvmsg() should wait here
The value returned by recvmsg() is 72
Kernel message: Progger:7,root,1537,1533,1261,4s,192.168.xxx.xxx,5001
The contents of the buffer is: Progger:7,root,1537,1533,1261,4s,192.168.xxx.xxx,5001
The length of the buffer is: 54
The struct member msghdr.msg_namelen has the value : 12 before zeroing out
The struct member msghdr.msg_namelen has the value : 0 after zeroing out
The struct member msghdr.msg_namelen has the value : 12 after initialization
Waiting to receive message
recvmsg() should wait here
The value returned by recvmsg() is 72
Kernel message: Progger:7,root,1537,1533,1261,4s,192.168.xxx.xxx,5001
The contents of the buffer is: Progger:7,root,1537,1533,1261,4s,192.168.xxx.xxx,5001
The length of the buffer is: 54
服务器示例输出
Waiting for initial connection in doProcessing() while loop
The length of the buffer is 54
Here is the message: Progger:7,root,1537,1533,1261,4s,192.168.xxx.xxx,5001
Waiting for initial connection in doProcessing() while loop
The length of the buffer is 54
Here is the message: Progger:7,root,1537,1533,1261,4s,192.168.xxx.xxx,5001
Waiting for initial connection in doProcessing() while loop
The length of the buffer is 54
Here is the message: Progger:7,root,1537,1533,1261,4s,192.168.xxx.xxx,5001
Waiting for initial connection in doProcessing() while loop
The length of the buffer is 54
Here is the message: Progger:7,root,1537,1533,1261,4s,192.168.xxx.xxx,5001
据我所知,考虑到Netlink,这可能难以重现。在此先感谢您的帮助,并为长篇文章感到抱歉。
编辑:我已更改代码以检查recvmsg()中的错误,如同建议但输出完全相同。