1. 程式人生 > >核心態socket程式設計

核心態socket程式設計

記不清從哪個kernel版本開始,核心態就不能直接使用系統呼叫了。當然,socket的系統呼叫也不能用了。不過好在kernel提供了一組核心態的socket API。在net/socket.c檔案中,可以看到這麼幾個匯出符號:

[cpp] view plaincopyprint?
  1. EXPORT_SYMBOL(kernel_sendmsg);  
  2. EXPORT_SYMBOL(kernel_recvmsg);  
  3. EXPORT_SYMBOL(sock_create_kern);  
  4. EXPORT_SYMBOL(sock_release);  
  5. EXPORT_SYMBOL(kernel_bind);  
  6. EXPORT_SYMBOL(kernel_listen);  
  7. EXPORT_SYMBOL(kernel_accept);  
  8. EXPORT_SYMBOL(kernel_connect);  
  9. EXPORT_SYMBOL(kernel_getsockname);  
  10. EXPORT_SYMBOL(kernel_getpeername);  
  11. EXPORT_SYMBOL(kernel_getsockopt);  
  12. EXPORT_SYMBOL(kernel_setsockopt);  
  13. EXPORT_SYMBOL(kernel_sendpage);  
  14. EXPORT_SYMBOL(kernel_sock_ioctl);  
  15. EXPORT_SYMBOL(kernel_sock_shutdown);  

基本上,在使用者態的socket的API,在核心態都有對應的API。

下面是一個專案中的程式碼,socket操作我加了注視。不用去關心程式碼功能,只要看一下socket部分的操作即可,非常簡單。

[cpp]view plaincopyprint?
  1. #include <linux/socket.h>
  2. #include <linux/net.h>
  3. #include <linux/in.h>
  4. struct fsg_common{  
  5. ....  
  6.         struct
     socket *encrypt_sock;   
  7.         struct msghdr encrypt_msg;  
  8.         struct sockaddr_in encrypt_servaddr;  
  9.         struct data_pkt *encrypt_pkt;  
  10. }  
  11. staticint encrypt_socket_init(struct fsg_common *common)  
  12. {  
  13.     struct socket *sock;  
  14.     int ret;  
  15.     char *dst_addr = "111.111.111.111";  
  16.     /* init servaddr */
  17.     memset(&common->encrypt_servaddr, 0, sizeof(common->encrypt_servaddr));  
  18.     common->encrypt_servaddr.sin_family = AF_INET;  
  19.     common->encrypt_servaddr.sin_port = htons(9999);  
  20.     //kernel態的IP地址轉換函式,有兩個函式in4_pton和in6_pton,分別用於IPv4和IPv6
  21.     in4_pton(dst_addr, strlen(dst_addr), (u8*)&common->encrypt_servaddr.sin_addr, '\0', NULL);  
  22.     //核心態udp通訊地址使用struct msghdr封裝
  23.     common->encrypt_msg.msg_name = &common->encrypt_servaddr;  
  24.     common->encrypt_msg.msg_namelen = sizeof(common->encrypt_servaddr);  
  25.     //建立套接字,類似socket()函式,返回的sock指標就是後面資料傳遞用的套接字了
  26.     ret = sock_create_kern(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock);  
  27.     if (ret < 0 || NULL == sock) {  
  28.         ERROR(common, "init encrypt board socket fail\n");  
  29.         return ret;  
  30.     }  
  31.     common->encrypt_sock = sock;  
  32.     common->encrypt_pkt = kmalloc(sizeof(struct data_pkt), GFP_KERNEL);  
  33.     if (NULL == common->encrypt_pkt)  
  34.         return -1;  
  35.     return 0;  
  36. }  
  37. staticvoid encrypt_socket_close(struct fsg_common *common)  
  38. {  
  39.     //關閉套接字,類似使用者態的close()函式
  40.     sock_release(common->encrypt_sock);  
  41.     common->encrypt_sock = NULL;  
  42. }  
  43. staticint encrypt_data(struct fsg_common *common, u8* data, unsigned int size, loff_t offset)  
  44. {  
  45.     struct socket *sock = common->encrypt_sock;   
  46.     struct data_pkt *pkt = common->encrypt_pkt;  
  47.     struct sockaddr *pservaddr = (struct sockaddr *)&common->encrypt_servaddr;  
  48.     int servlen = sizeof(common->encrypt_servaddr);  
  49.     if (unlikely(NULL == sock || NULL == pkt || NULL == pservaddr))  
  50.         return -1;  
  51.     memset(pkt, 0, sizeof(struct data_pkt));  
  52.     unsigned int copied_size = 0;  
  53.     struct kvec vec;  
  54.     struct msghdr msg;  
  55.     memset(&msg, 0, sizeof(msg));  
  56.     while (copied_size < size) {  
  57.         pkt->res=0xffffffff;  
  58.         pkt->file_offset = offset;   
  59.         memcpy(pkt->data, data + copied_size, SECTOR_SIZE);  
  60.         //配置udp傳送資料地址及長度
  61.         vec.iov_base = (void *)pkt;  
  62.         vec.iov_len = sizeof(struct data_pkt);  
  63.         ret = kernel_sendmsg(sock, &common->encrypt_msg, &vec, 1, sizeof(struct data_pkt));  
  64.         printk("send data(return :%d):\n", ret);  
  65.         //接收udp報文
  66.         ret = kernel_recvmsg(sock, &msg, &vec, 1, sizeof(struct data_pkt), 0);  
  67.         printk("recv data(return :%d):\n", ret);  
  68.         memcpy(data+copied_size, pkt->data, 512);  
  69.         copied_size += 512;  
  70.     }     
  71.     return 0;  
  72. }