linux socket实现内核态和用户态通信
来源:互联网 发布:上海高级美工培训 编辑:程序博客网 时间:2024/05/22 03:13
最近有一个的需求,需要将一些linux用户态的命令做成自动化。
比如在用户态执行lspci命令,判断获取的设备中是否有某个型号的pci卡,这就需要linux内核态和用户态交互。实现的方法是通过linux内核态编程。在内核驱动中通过socket发送一个用户态请求,server端接收到请求并执行,执行后将结果返回给内核驱动,驱动中判断结果。
内核态socket编程的过程和用户态下的socket编程流程一样,但是接口不同。Kernel提供了一组内核态的socket API,基本上在用户态的sockt API在内核中都有对应的API。
在net/socket.c中可以看到导出符号:
主要实现:
server端代码:
#include <stdio.h>#include <string.h>#include <unistd.h>#include <ctype.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdlib.h>#include <errno.h>#include "public.h"#include <sys/time.h>#include <sys/ioctl.h>#include <fcntl.h>#include <netinet/in.h>#include <netinet/tcp.h>#include <errno.h>int server_listen_fd;int server_accept_fd;int port= 2002;int get_current_time(){ struct timeval stime; gettimeofday( &stime, NULL); return stime.tv_sec * 1000000 + stime.tv_usec;}int excute_cmd(char* cmd, char* result) { char buffer[1024]; //定义缓冲区 FILE* pipe = popen(cmd, "r"); if (!pipe) return 1; while (!feof(pipe)) { if (fgets(buffer, 1024, pipe)){ strcat(result,buffer); } } pclose(pipe); //关闭管道 return 0; }int server_recv(int fd, cmd_request *request, int len_recv, int timeout){ int len; unsigned int recved = 0; unsigned long last_time = get_current_time(); int temp_time; printf("server recv start %d time:%d!\n", len_recv, timeout); while (1) { temp_time = get_current_time() - last_time; if (get_current_time() - last_time > timeout * 1000) { printf("server recv timeout!\n"); break; } len = recv(fd, request->reqbuf + recved, len_recv - recved, MSG_DONTWAIT); printf("recv buf is %s:\n",request->reqbuf); if (len <= 0) { printf("server recv error!\n"); return -1; } printf("server has recv %d\n",len); recved += len; if (recved >= len_recv) { printf("recved %d bytes!\n", recved); return recved; } } return 0;}int server_accept(){ int size; int opt = 1; int flags; struct sockaddr_in server_accept_addr; bzero(&server_accept_addr, sizeof(server_accept_addr)); size = sizeof(server_accept_addr); flags = fcntl(server_accept_fd, F_GETFL, 0); fcntl(server_accept_fd, F_SETFL, flags | O_NONBLOCK); setsockopt(server_accept_fd, IPPROTO_TCP, TCP_NODELAY, (char *)&opt,sizeof(int));Step1: server_accept_fd = accept(server_listen_fd, (struct sockaddr*)&server_accept_addr, &size); if (server_accept_fd < 0) { if (errno == EAGAIN) { goto Step1; } perror("error:socket accept1 exited!\n"); exit(1); } }int server_init(char *ip){ int opt =1; int flags; struct sockaddr_in server_listen_addr; bzero(&server_listen_addr, sizeof(server_listen_addr)); server_listen_addr.sin_family = AF_INET; server_listen_addr.sin_addr.s_addr = inet_addr(ip); server_listen_addr.sin_port = htons(port); setsockopt(server_listen_fd, SOL_SOCKET, SO_REUSEADDR,(char *)&opt, sizeof(int)); if (bind(server_listen_fd, (struct sockaddr*)&server_listen_addr, sizeof(server_listen_addr)) == -1) { perror("can't to bind"); exit(1); } flags = fcntl(server_listen_fd, F_GETFL, 0); fcntl(server_listen_fd, F_SETFL, flags | O_NONBLOCK); if (listen(server_listen_fd, 10) == -1) { perror("can't to bind"); exit(1); } return 0;}int main(int argc,char *argv[]){ int ret; int flags; int timeout = 1000; struct sockaddr_in server_send_addr; cmd_request request; cmd_response response; //printf("argv is %s\n", argv[1]); if (!argv[1]) { printf("need ip!\n"); return -1; } bzero(&server_send_addr, sizeof(server_send_addr)); memset(&request, 0 ,sizeof(request)); memset(&response, 0 ,sizeof(response)); server_listen_fd = socket(AF_INET,SOCK_STREAM,0); if (-1 == server_listen_fd) { perror("fail to create socket!"); exit(1); } server_init(argv[1]); while (1) { printf("server socket begin accept:\n"); server_accept(); //recv ret = server_recv(server_accept_fd, &request, sizeof(cmd_request), timeout); if (ret <= 0) { printf("server recv error!\n"); } //ret = recv(server_accept_fd, request.reqbuf, 1024, 0); printf("DATA:[%s]\n", request.reqbuf); excute_cmd(request.reqbuf,response.rspbuf); printf("the result is %s",response.rspbuf); //send ret = send(server_accept_fd, response.rspbuf, sizeof(response.rspbuf), 0); if (ret <= 0){ printf("send %d failed!\n",ret); } } close(server_accept_fd); return 0;}
客户端实现:
#include <linux/module.h>#include <linux/init.h>#include <linux/socket.h>#include <net/sock.h>#include <linux/in.h>#include <linux/tcp.h>#include <linux/in.h>#include <linux/inet.h>#include <linux/time.h>#include "public.h"int port_id = 2002;char * dst_ip = "192.168.0.103";module_param(dst_ip, charp, S_IRUSR);cmd_request *prequest;cmd_response *presponse;int client_init(void);int plugin_get_current_time(){ struct timeval stime; do_gettimeofday(&stime); return (stime.tv_sec * 1000000 + stime.tv_usec) / 1000;}int client_send(struct socket *sock, unsigned char *pbufsend, int len_send){ int len; int sended = 0; unsigned long last_time = plugin_get_current_time(); struct kvec vec; struct msghdr msg; unsigned short timeout = 1000; while (1) { if (plugin_get_current_time() - last_time > timeout){ printk("kernel send msg timeout!\n"); break; } vec.iov_base = pbufsend + sended; vec.iov_len = len_send - sended; msg.msg_flags = 0; len = kernel_sendmsg(sock, &msg, &vec, 1, len_send - sended); if (len < 0){ if (len == -EWOULDBLOCK){ printk("kernel send msg would block!\n"); continue; } else { printk("kernel send msg failed with < 0!\n"); return -EINVAL; } } else if (len == 0){ printk("kernel send msg failed with = 0!\n"); return -EINVAL; } sended += len; if (sended >= len_send) { printk("kernel send %d bytes!\n", sended); return sended; } }}int client_init(void){ struct socket *sock; struct sockaddr_in s_addr; int ret = 0; sock = (struct socket*)kmalloc(sizeof(struct socket), GFP_KERNEL); memset(&s_addr, 0, sizeof(s_addr)); s_addr.sin_family = AF_INET; s_addr.sin_port = htons(port_id); s_addr.sin_addr.s_addr = in_aton(dst_ip); /*create socket*/ ret = sock_create_kern(AF_INET, SOCK_STREAM, 0, &sock); if (ret) { printk("socket create failed\n"); return ret; } printk("create socket ok!\n"); /*connect server*/ ret = sock->ops->connect(sock, (struct sockaddr*)&s_addr, sizeof(struct sockaddr_in), 0); if (ret) { printk("socket connect server failed!\n"); return ret; } printk("connect server ok!\n"); // set opt int opt = 1; int flags; kernel_setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&opt, sizeof(int)); flags = kernel_sock_ioctl(sock, F_GETFL, 0); kernel_sock_ioctl(sock, F_SETFL, flags | O_NONBLOCK); /*kmalloc sendbuf*/ char *sendbuf = NULL; sendbuf = kmalloc(1024, GFP_KERNEL); memset(sendbuf, 0, 1024); strcpy(sendbuf, "lspci"); printk("the request is %s, size is %d\n", sendbuf, sizeof(sendbuf)); ret = client_send(sock, sendbuf, 1024); if (ret <= 0) { printk("client send failed !\n"); return -EINVAL; } recvbuf = kmalloc(1024, GFP_KERNEL); memset(recvbuf, 0, 1024); memset(&msg, 0, sizeof(msg)); memset(&vec, 0, sizeof(vec)); vec.iov_base = recvbuf; vec.iov_len=1024; int count = 0; while (count < 1000) { ret = kernel_recvmsg(sock, &msg, &vec, 1, 1024, 0); if(ret < 0){ printk("client:kernel_sendmsg error!\n"); return ret; } else if (ret > 0) { printk("recv message %s\n",recvbuf); break; } count ++; } if (count >= 1000) printk("kernel recv msg timeout!\n"); //判断结果是否符合预期 char *expect = "PCI"; if (strstr(recvbuf, expect) != NULL) { printk("lspci test pass!\n"); } return ret;}#if 0int tc_run(skip_tc *pskip_tc){ socket *psock; pskip_tc->desc = psock; client_init(); client_recv_and_send(pskip_tc,pskip_tc->request,sizeof(cmd_request),pskip_tc->response,sizeof(cmd_response));}#endifstatic int __init plugin_init(void){ printk("hello, plugin!\n"); client_init(); return 0;}static void __exit plugin_exit(void){ printk("goodbye,plugin!\n");}module_init(plugin_init);module_exit(plugin_exit);MODULE_LICENSE("GPL");
使用示例:
服务端:
客户端:
0 0
- linux socket实现内核态和用户态通信
- linux用户态和内核态通信
- Linux用户态和内核态通信
- netlink socket 用户态和内核态的通信
- netlink socket实现内核和用户的通信
- 内核态和用户态通信(二)--实现
- linux用户态和内核态通信之netlink机制
- linux用户态和内核态通信之netlink机制
- linux系统用户态和内核态及其通信
- linux 用户态和内核通信之Netlink
- linux内核和用户通信
- Linux用户和内核空间之间的通信实现
- 2.6.27内核 netlink socket实现内核和用户的通信
- linux内核空间和用户空间通信
- linux用户和内核之间通信
- socket的内核和上层通信机制(netlink) -- linux内核
- Linux用户态与内核态交互数据---socket函数
- linux用户态与内核态通信netlink
- PAT--1126. Eulerian Path
- sqlhelper重构
- poj-3641(Pseudoprime numbers)
- system.exit(0) system.exit(1) 含义与区别
- 从百度统计看到的一些有意思的事情
- linux socket实现内核态和用户态通信
- deeplearning 打卡第四天_线性代数基础_1
- Android与H5的交互
- HRBUST1315-火影忍者之~大战之后
- 简单易用的json解析,json生成器和基于JSONArray和JSONObject for Android的数据存储
- 2017.3.5
- 关于GetWindowTextA()和GetWindowTextW()和GetWindowText()的区别
- Dijkstra算法详解
- hdu5078 Osu!