歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

網絡編程常用接口的內核實現----sys_socket()

最近在開發一個內核模塊,主要的功能是在集群的節點之間遷移TCP連接,從而實現基於內容的調用。因此,花了很多時間和精力研究linux的網絡協議棧,但是還是有很多地方沒有串起來。網絡協議棧是為用戶層的應用開發服務的,因此決定從用戶層常用的編程接口入手,通過學習這些接口的實現,來理清整個過程,加深對網絡協議棧的理解。

網絡編程通常是基於客戶端-服務端模型。首先啟動服務器,稍後的某個時刻啟動客戶,它要連接到此服務器上。假設客戶給服務器發送一個請求,服務器處理這個請求,並且給客戶發送一個響應。為了執行網絡I/O,第一件事情就是調用socket()函數來創建套接字。socket()函數對應的系統調用時sys_socket(),其源碼及分析如下所示:

SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)
{
 int retval;
 struct socket *sock;
 int flags;

 /* Check the SOCK_* constants for consistency.  */
 /*
  * 下面的檢查是在編譯的時候進行的,如果這些
  * 變量的值不一致,編譯時會報錯。
  */
 BUILD_BUG_ON(SOCK_CLOEXEC != O_CLOEXEC);
 BUILD_BUG_ON((SOCK_MAX | SOCK_TYPE_MASK) != SOCK_TYPE_MASK);
 BUILD_BUG_ON(SOCK_CLOEXEC & SOCK_TYPE_MASK);
 BUILD_BUG_ON(SOCK_NONBLOCK & SOCK_TYPE_MASK);

 /*
  * 從linux 2.6.27開始,參數type除了指定套接字類型外,還
  * 可以通過或運算來指定SOCK_CLOEXEC和SOCK_NONBLOCK標志
  * 來改變套接字的行為。可以通過man socket命令查看詳情。
  * 首先通過SOCK_TYPE_MASK掩碼來獲取type中設置的標志(當然
  * 也可能沒有設置)。如果type中有標志設置,但是不是
  * SOCK_CLOEXEC和SOCK_NONBLOCK對應的位,則返回EINVAL錯誤。
  */
 flags = type & ~SOCK_TYPE_MASK;
 if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
  return -EINVAL;
 /*
  * 獲取套接字類型
  */
 type &= SOCK_TYPE_MASK;

 /*
  * 如果SOCK_NONBLOCK不等於O_NONBLOCK並且設置了SOCK_NONBLOCK
  * 標志,則將flags中的SOCK_NONBLOCK替換為O_NONBLOCK。
  */
 if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
  flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;

 /*
  * 根據協議族類型和套接字類型創建套接字。
  */
 retval = sock_create(family, type, protocol, &sock);
 if (retval < 0)
  goto out;

 /*
  * 創建一個新的文件描述符,將新創建的
  * socket實例關聯上去。
  */
 retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK));
 if (retval < 0)
  goto out_release;

out:
 /* It may be already another descriptor 8) Not kernel problem. */
 return retval;

out_release:
 sock_release(sock);
 return retval;
}

Copyright © Linux教程網 All Rights Reserved