Socket Programming.

Slides:



Advertisements
Similar presentations
網路程式設計 (Network Programming)
Advertisements

第五章 網際網路 5-1 網際網路的歷史沿革 5-2 網際網路基本運作原理 5-3 連線媒介與連線上網 5-4 網際網路上的熱門應用
第 12 章 UDP 與 TCP.
马志强 软件学院501室 网络应用开发 马志强 软件学院501室
Chapter 12 UDP 與 TCP.
第2章 计算机网络的协议与体系结构 2.1 计算机网络体系结构的形成 2.2 协议与划分层次 2.3 计算机网络的原理体系结构
第1章 概述.
操作系统结构.
Netman Linux 的防火牆設計與應用 Netman
Socket.
天文望远镜集成建模研究 杨德华 南京天文光学技术研究所 30 NOV, 年中国虚拟天文台年会 广西师范大学 桂林
计算机网络实验介绍 信息网络实验室 2017/9/13 04:55:22.
Leftmost Longest Regular Expression Matching in Reconfigurable Logic
Lab312.
An Adaptive Cross-Layer Multi-Path Routing Protocol for Urban VANET
Group multicast fanOut Procedure
传输层是整个协议层次的核心,其任务是在源机器和目标机器之间提供可靠的、性价比合理的数据传输功能,并与当前所使用的物理网络完全独立
Advanced Sockets Programming
第 12 章 UDP 與 TCP.
TCP、UDP 通信实践 广州创龙电子科技有限公司 01 广州创龙电子科技有限公司
Operating System Concepts 作業系統原理 Chapter 3 行程觀念 (Process Concept)
第 13 章 DNS 著作權所有 © 旗標出版股份有限公司.
通訊協定 OSI分層模式 與 TCP/IP協定
Socket Programming in C
第五章 網際網路 5-1 網際網路的歷史沿革 5-2 網際網路基本運作原理 5-3 連線媒介與連線上網 5-4 網際網路上的熱門應用
Socket 基本觀念.
附錄 通訊協定堆疊.
Operating System Concepts 作業系統原理 CHAPTER 2 系統結構 (System Structures)
TCP/IP Protocol Suite TCP/IP協定 第二組 投影片製作by簡嘉宏 綦凱宏 林睿敏 滕孟哲.
系統與網路管理工具.
Socket Programming.
第4章 网络互联与广域网 4.1 网络互联概述 4.2 网络互联设备 4.3 广域网 4.4 ISDN 4.5 DDN
Chapter 3 行程觀念 (Process Concept)
创建型设计模式.
在一定程度上 人类的思维产生于 简单个体之间的相互作用 ——Marvin Minsky.
什麼是網際網路? 面臨攻擊的網路 網路邊際 總結 網路核心
套接字API调用.
第十讲 TCP协议 协议概述 报文段格式 差错控制 流控和拥塞控制 TCP连接管理 TCP性能问题 TCP软件设计 2018/12/7
預官考試輔導 計算機概論提要 91年12月4日.
重點 資料結構之選定會影響演算法 選擇對的資料結構讓您上天堂 程式.
第七讲 网际协议IP.
NS2 – TCP/IP Simulation How-Wei Wu.
第2章 套接字网络编程基础 2.1 UNIX套接字网络编程接口的 产生与发展 2.2 套接字编程的基本概念 2.3 面向连接的套接字编程
校園網路架構介紹與資源利用 主講人:趙志宏 圖書資訊館網路通訊組.
第5讲 网络层 本讲目的: 概述: 理解网络层服务原理: 因特网的实现实例 网络层的服务 路由选择原理 分层的路由选择 IP协议
第 12 章 UDP 與 TCP 著作權所有 © 旗標出版股份有限公司.
單元11: 事件結構 主題: a. 事件結構概述 b. 如何使用事件結構 c. 使用事件結構須注意的事項.
Westmont College 网络互连 Part 4 (传输协议, UDP and TCP, 协议端口)
Web Server 王宏瑾.
Westmont College 网络应用软件 第一讲 (客户-服务器 概念, 协议端口的使用, 套接字API)
資料結構 Data Structures Fall 2006, 95學年第一學期 Instructor : 陳宗正.
資料庫 靜宜大學資管系 楊子青.
Version Control System Based DSNs
Advister: Quincy Wu Speaker: Chenglin Tsai Date:3/26
3.1 通訊協定 3.2 開放系統參考模式(OSI) 3.3 公眾數據網路 3.4 TCP/IP通訊協定
Speaker: Liu Yu-Jiun Date: 2009/4/29
中国科学技术大学计算机系 陈香兰 2013Fall 第七讲 存储器管理 中国科学技术大学计算机系 陈香兰 2013Fall.
虚 拟 仪 器 virtual instrument
傳輸控制協議 /互聯網協議 TCP/IP.
Source: Journal of Network and Computer Applications, Vol. 125, No
SOCKET( ).
Inheritance -II.
NASA雜談+電腦網路簡介 Prof. Michael Tsai 2015/03/02.
2019/5/3 JAVA Socket(UDP).
Chapter 10 Mobile IP TCP/IP Protocol Suite
Mobile IPv4.
Operating System Software School of SCU
助教:廖啟盛 JAVA Socket(UDP) 助教:廖啟盛
Internet课程设计 教师:陈 妍 朱海萍 西安交通大学计算机系
Principle and application of optical information technology
Presentation transcript:

Socket Programming

Socket Programming Open Source Implementation: Linux Socket Filter TCP/IP 簡介 TCP/IP模組架構 Socket介紹 Socket分類 Client/Server model(主從式架構模型) 相關函式 TCP Socket程式設計 UDP Socket程式設計 Socket Read/Write Inside Out Performance Matters: Interrupt and Memory Copy at Socket Open Source Implementation: Linux Socket Filter

TCP/IP 簡介 TCP/IP 的全稱是Transmission Control Protocol / Internet Protocol (TCP/IP) 當初是用來配合ARPANET 來處理不同硬體之間的連接問 題的。 ARPANET除了研發出一套可靠的資料通訊技術外,還同 時要兼顧跨平臺作業,從而奠定了今日的網際網路模式。 TCP/IP是一組支援網路溝通協定的集合 ARPANET(網際網路的前身) 那TCP/IP主要的工作是什麼呢 是定義網路送實的資料單位 並說明一個資料單位應包含哪些資訊 ,以便讓接收此資料單元的電腦可以正確的解析訊息

TCP/IP模組架構 一個TCP/IP模組架構包含4個階層,分為網路存取層、 網際網路層、傳輸層和應用層 階層 說明 網路存取層 提供一個與實體網路之間的介面 網際網路層 提供與硬體無關的邏輯位置,並將封包(Packet)發送至網路上,並讓他們獨立的到達目的地。 傳輸層 為網際網路提共流程控制、錯誤檢查、回報服務,是與網路應用程式間的介面。 應用層 為網路除錯、檔案傳輸、遠端控制和網際網路活動提供應用程式。 網路存取層 提供一個與實體網路之間的界面,可讓主機具有與網路連接並發送IP封包的能力。 網際網路層 提供與硬體無關的邏輯位址,並將資料封包(packet)發送至網路上,並讓它們獨立的到達目的地。在此層中定義[IP協定](internet protocol),此協定為網際網路上的電腦,提供一個共同的定址結構,稱為IP位址。 傳輸層 為網際網路提供流程控制、錯誤檢查、回報服務,是與網路應用程式間的界面。TCP/IP模組定義二組協定,TCP和UDP。TCP是一個連結協定,透過TCP可確保接收端收到完整、正確的資料。另一方面,UDP則是一個非連結協定,比TCP快,但可靠度差。 應用層 為網路除錯、檔案傳輸、遠端控制和網際網路活動提供應用程式,包含FTP、HTTP、SMTP、TELNET、與DNS等功能。

Socket 介紹 socket 是一種可做雙向資料傳輸的通道, Linux程序可經由此裝置與本地端或是遠端的 程序做溝通。 A socket is an abstraction of the end point of a communication channel. As its name suggests, the “end-to-end” protocol layer controls the data communications between the two end points of a channel. The end points are created by networking applications using socket APIs of an appropriate type. Networking applications can then perform a series of operations on that socket. The operations that can be performed on a socket include control operations (such as associating a port number with the socket, initiating or accepting a connection on the socket, or releasing the socket), data transfer operations (such as writing data through the socket to some peer application, or reading data from some peer application through the socket), and status operations (such as finding the IP address associated with the socket). The complete set of operations that can be performed on a socket constitutes the socket APIs. To open a socket, an application program first calls the socket() function to initialize an end-to-end channel. The standard socket call, sk=socket(domain, type, protocol) , requires three parameters. The first parameter specifies the domain or address family. Commonly used families are AF_UNIX for communications bounded on the local machine, and AF_INET for communications based on IPv4 protocols. The second parameter specifies the type of socket. Common values for socket type, when dealing with the AF_INET family, include SOCK_STREAM (typically associated with TCP) and SOCK_DGRAM (associated with UDP). Socket type influences how packets are handled by the kernel before being passed up to the application. The last parameter specifies the protocol that handles the packets flowing through the socket. The socket function returns a file descriptor through which operations on the socket can be applied. The values of the socket parameters depend on what underlying protocols are used. In the next two subsections we investigate three types of socket APIs. They correspond to accessing the transport layer, the IP layer, and the link layer, respectively, as we can see in their open source implementations.

Socket分類 (1)Datagram sockets(connectionless) 資料在datagram sockets間是利用UDP封包傳送,因此 接收端socket可能會收到次序錯誤的資料,且其中部分資料 亦可能會遺失。 (2)Stream sockets(connection-oriented) 資料在stream sockets間是利用TCP封包來傳送,因此 接收端socket可以收到順序無誤、無重覆、正確的資料。此 外TCP傳送時是採資料流的方式,因在傳送時會所有資料會 視情況被分割在數個TCP封包中。 在TCP/IP架構下,Socket可以分為下面兩類

Client/Server model 每個網路應用程式都有一個通訊端點,一種端點是 用戶端,另一種是伺服器。根據定義,用戶端會先送出 第一個封包,由一個伺服器接收。在初步接觸後,用戶 端和伺服器均能開始收送資料。 依據socket所提供的服務來將它分類,然而在用戶 端和伺服器上的這兩個sockets必須是同一類才能互相通 訊,也就是說,他們必須都是stream(TCP)或都是 datagram(UDP)。 用戶端的應用程式必須要能找到並識別伺服器的socket, 而伺服器會將它的socket命名以讓用戶端識別, 就TCP/IP而言,一個socket name包括了IP位址、連結埠編號、以及協定本身。 用戶端可用Windows Sockets的名稱伺服函式來查到標準伺服器的連結埠編號, 而如果知道伺服器的主機名,則可以Windows Sockets的主機名稱分析函式,來查得伺服器的IP。 當用戶端socket成功地聯繫上伺服器端之socket後,這兩者便形成一個“結合”(association)。 在此時,每個socket都可以由它的名字及對方的名字所形成的組合加以識別。 這個結合包括五個要素:所用的協定、用戶端IP位址、用戶端連結埠號碼、伺服器端IP位址、伺服器端連結埠號碼。 這個“結合”的觀念並不只是Windows Sockets程式設計的基礎,它也是一般網路通訊的重要觀念。 在結合中的資訊可識別及引導封包通過網路,從這一端的程式傳至另一端。

相關函式socket() NAME socket() - create an endpoint for communication SYNOPSIS #include <sys/types.h> #include <sys/socket.h> int socket(int domain, int type, int protocol); 1. 由server和client使用 2. domain: 設AF_INET 3. type: SOCK_STREAM或SOCK_DGRAM 4. protocol: 0 (讓socket()根據type自動設定)。 5. 成功傳回socket descriptor,失敗傳回-1 (並使用errno的macro) socket() 創建一個新的確定類型的套接字,類型用一個整型數值標識(文件描述符),並為它分配系統資源。 socket() 為通訊創建一個端點,為套接字返回一個文件描述符。 socket() 有三個參數: domain 為創建的套接字指定協議集。 例如: AF_INET 表示IPv4網路協議 AF_INET6 表示IPv6 AF_UNIX 表示本地套接字(使用一個文件) type 如下: SOCK_STREAM (可靠的面向流服務或流套接字) SOCK_DGRAM (數據報文服務或者數據報文套接字) SOCK_SEQPACKET (可靠的連續數據包服務) SOCK_RAW (在網路層之上的原始協議) protocol 指定實際使用的傳輸協議。 最常見的就是IPPROTO_TCP、IPPROTO_SCTP、IPPROTO_UDP、IPPROTO_DCCP。這些協議都在<netinet/in.h>中有詳細說明。 如果該項為「0」的話,即根據選定的domain和type選擇使用預設協議。 如果發生錯誤,函數返回值為-1。 否則,函數會返回一個代表新分配的描述符的整數。

相關函式bind() NAME bind() - bind a name to a socket SYNOPSIS #include <sys/types.h> #include <sys/socket.h> int bind(int sockfd, struct sockaddr *my_addr, int addrlen); 1. 由server使用 2. sockfd為socket()的回傳值。 3. myaddr 須指定port和ip後傳入,注意是用struct sockaddr_in宣告 ,傳入時轉為struct sockaddr。 4. addrlen直接用 sizeof(struct sockaddr) 5. bind就是將local的endpoint attach到一個socket bind() 一般用於伺服器端,將一個套接字與一個套接字地址結構相關聯,比如,一個指定的本地埠和IP位址。 bind() bind() 為一個套接字分配地址。當使用socket()創建套接字後,只賦予其所使用的協議,並未分配地址。在接受其它主機的連接前,必須先調用bind()為套接字分配一個地址。bind()有三個參數: sockfd, 表示使用bind函數的套接字描述符 my_addr, 指向sockaddr結構(用於表示所分配地址)的指針 addrlen, 用socklen_t欄位指定了sockaddr結構的長度 如果發生錯誤,函數返回值為-1,否則為0。

相關函式connect() NAME connect() - initiate a connection on a socket. SYNOPSIS #include <sys/types.h> #include <sys/socket.h> int connect(int sockfd, struct sockaddr *serv_addr, int addrlen); 1. connect()由client呼叫 2. sockfd由socket()產生,serv_addr指定server的ip和port後傳入 3. addrlen直接用 sizeof(struct sockaddr) connect() 用於客戶端,為一個套接字分配一個自由的本地埠號。 如果是TCP套接字的話,它會試圖獲得一個新的TCP連接。 connect()系統調用為一個套接字設置連接,參數有文件描述符和主機地址。 某些類型的套接字是無連接的,大多數是UDP協議。對於這些套接字,連接時這樣的:默認發送和接收數據的主機由給定的地址確定,可以使用 send()和 recv()。 返回-1表示出錯,0表示成功。

相關函式listen() NAME listen() - listen for connections on a socket SYNOPSIS #include <sys/socket.h> int listen(int sockfd, int backlog); 1. 由server使用 2. sockfd由socket()產生,backlog設定可queue住的connection數量 (等待accept())。 3. 失敗傳回-1 listen() 用於伺服器端,使一個綁定的TCP套接字進入監聽狀態。 當socket和一個地址綁定之後,listen()函數會開始監聽可能的連接請求。然而,這只能在有可靠數據流保證的時候使用,例如:數據類型(SOCK_STREAM,SOCK_SEQPACKET)。 listen()函數需要兩個參數: sockfd, 一個socket的描述符. backlog, 一個決定監聽隊列大小的整數,當有一個連接請求到來,就會進入此監聽隊列,當隊列滿後,新的連接請求會返回錯誤。 一旦連接被接受,返回0表示成功,錯誤返回-1。

相關函式accept() NAME accept() - accept a connection on a socket SYNOPSIS #include <sys/types.h> #include <sys/socket.h> int accept(int sockfd, struct sockaddr *addr, int *addrlen); 1. sockfd: listen()所使用的那個sockfd 2. addr 宣告完就拿來用,將存放client的資訊 3. addrlen直接用 sizeof(struct sockaddr) 4. 失敗傳回-1 5. server listen()完後開始等待accept()。 accept()傳回一個file descriptor以供此connection的I/O之用。 accpet完之後,server繼續使用listen()的fd等待下一個connection。 accept() 用於伺服器端。 它接受一個從遠端客戶端發出的創建一個新的TCP連接的接入請求,創建一個新的套接字,與該連接相應的套接字地址相關聯。 當應用程序監聽來自其他主機的面對數據流的連接時,通過事件(比如Unix select()系統調用)通知它。必須用accept()函數初始化連接。 Accept() 為每個連接創立新的套接字並從監聽隊列中移除這個連接。它使用如下參數: sockfd,監聽的套接字描述符 cliaddr, 指向sockaddr 結構體的指針,客戶機地址信息。 addrlen,指向 socklen_t的指針,確定客戶機地址結構體的大小 。 返回新的套接字描述符,出錯返回-1。進一步的通信必須通過這個套接字。 Datagram 套接字不要求用accept()處理,因為接收方可能用監聽套接字立即處理這個請求。

相關函式sendto() int sendto(int sockfd, const void *msg , int len, int flags); 1. sockfd可以是listen()的fd或是accpet的fd。 2. msg就是data,len就是data 的length (sizeof(msg)) ,flag就設0。 3. 回傳值為送出去的大小 4. 失敗傳回-1 send()和recv(),或者write()和read(),或者recvfrom()和sendto(), 用於往/從遠程套接字發送和接受數據。 從已經開啟的socket傳送資料 格式 #include <sys/types.h> #include <sys/socket.h> int send(int s, const void *msg, int len, unsigned int flags); 其中的引數說明: ru; y xul4 將buf指向的資料經由socket傳送到遠端,len為可傳送的最大長度,flags一般設為0 引數 說明 MSG_OOB 接收的資料以out-of-band送出 MSG_DONTROUTE 取消route的查詢 MSG_DONTWAIT 傳送過程不可以被阻斷 MSG_NOSIGNAL 傳送動作不會因SIGPIPE訊號中斷 傳回值 成功:傳回傳送的字元數 失敗:傳回-1

相關函式recvfrom() The recvfrom() call is similar in many respects: int recvfrom(int sockfd, void *buf , int len, unsigned int flags); 1. sockfd: 要從哪個fd接收。 2. 回傳值為收到的大小。若回傳0,表示對方把connection切了。 send()和recv(),或者write()和read(),或者recvfrom()和sendto(), 用於往/從遠程套接字發送和接受數據。 從已經開啟的socket接收資料 格式 #include <sys/types.h> #include <sys/socket.h> int recv(int s, void *buf, int len, unsigned int flags); 其中的引數說明: 將資料存到buf指向的記憶體,len為可接收的最大長度,flags一般設為0 引數 說明 MSG_OOB 接收以out-of-band送來的資料 MSG_PEEK 遠端socket傳來的資料,不會在接收受刪除 MSG_WAITALL 固定接收len引數指定長度的資料,除非有錯誤或訊號發生 MSG_NOSIGNAL 接收動作不會因SIGPIPE訊號中斷 傳回值 成功:傳回接收的字元數 失敗:傳回-1  

相關函式write() write() NAME write() - write to a file descriptor SYNOPSIS #include <unistd.h> ssize_t write(int fd, const void *buf, size_t count); 1. 可寫到file,device或socket 將資料寫入已經開啟的socket 格式 #include <sys/socket.h> int write(int sockfd, char *buf, int len); 其中的引數說明: 引數 說明 Sockfd socket函數執行後傳回的socket ID Buf 指向字元暫存器的指標,用來存放讀取到的資料 Len 欲讀取的字元長度。 傳回值 成功:傳回寫入的字元數 失敗:傳回-1  

相關函式read() read() NAME read() - read from a file descriptor SYNOPSIS #include <unistd.h> ssize_t read(int fd, void *buf, size_t count); 1. 從file,device或socket讀取 2. 沒有data則read會block 3. count指定要讀的長度,如果沒有那麼多,則return,不會block 從已經開啟的socket讀取資料 格式 #include <sys/socket.h> int read(int sockfd, char *buf, int len); 其中的引數說明: 引數 說明 Sockfd socket函數執行後傳回的socket ID Buf 指向字元暫存器的指標,用來存放讀取到的資料 Len 欲讀取的字元長度。 傳回值 成功:傳回接收的字元數 失敗:傳回-1   write()

相關函式close() close() NAME read() - read from a file descriptor SYNOPSIS #include <unistd.h> int clode(int sockfd); 1.呼叫close() 若成功:傳回0 失敗:傳回-1

TCP Socket程式設計 Similarly, a socket file descriptor returned from socket(AF_INET, SOCK_ STREAM, IPPROTO_TCP) is initialized as a TCP socket, where AF_INET indicates Internet address family, SOCK_STREAM stands for the reliable byte-stream service, and IPPROTO_TCP means the TCP protocol. The functions to be performed on the descriptor are depicted in Figure 5.38 . Here by default bind() is not called at the client. The flowchart of the simple TCP client-server programs is a little bit complex due to the connection-oriented property of TCP. It contains connection establishment, data transfer, andconnectionterminationstages. Besides bind() , theservercalls listen() to allocate the connection queue to the socket and waits for connection requests from clients. The listen() system call expresses the willingness of the server to start accepting incoming connection requests. Each listening socket contains two queues: (1) partially established request queue and (2) fully established request queue. A request would first stay in the partially established queue during the three-way handshake. After the connection is established with the three-way handshake finished, the request would be moved to the fully established request queue. The partially established request queue in most operating systems has a maximum queue length, e.g., 5, even if the user specifies a value larger than that. Thus, the partially established request queue could be the target of a denial of service (DoS) attack. If a hacker continuously sends SYN requests without finishing the three-way handshake, the request queue will be saturated and cannot accept new connection requests from well-behaving clients. The listen() system call is commonly followed by the accept() system call, whose job is to de-queue the first request from the fully-established request queue, initialize a new socket pair and return the file descriptor of the new socket created for the client. That is, the accept() system call provided by the BSD socket results in the automatic creation of a new socket, largely different from that in the TLI sockets where an application must explicitly create a new socket for the new connection. Note that the original listening socket is still listening on the well-known port for new connection requests. Of course the new socket pair contains the IP

UDP Socket程式設計 The services most widely used by networking applications are those provided by transport protocols such as UDP and TCP. A socket file descriptor is returned from the socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) function and 392 Computer Networks: An Open Source Approach initialized as a UDP socket, where AF_INET indicates Internet address family, SOCK_DGRAM stands for datagram service, and IPPROTO_UDP indicates the UDP protocol. A series of operations can be performed on the descriptor, such as those functions in Figure 5.37 . In Figure 5.37 , before the connection is established, the UDP server as well as the client creates a socket and uses the bind() system call to assign an IP address and a port number to the socket. Note that bind() is optional and is usually not called at the client. When bind() is not called, the kernel selects the default IP address and a port number for the client. Then, after a UDP server binds to a port, it is ready to receive requests from the UDP client. The UDP client may loop through the sendto() and recvfrom() functions to do some useful work until it finishes its job. The UDP server continues accepting requests, processing the requests, and feedbacking the results using sendto() and recvfrom() . Normally, a UDP client does not need to call bind() as it does not need to use well-known ports. The kernel dynamically assigns an unused port to the client when it calls sendto() .

所有的網路應用程式皆可分為五個步驟: 開啟一個socket 為socket命名 與另一個socket結合 在sockets間收送資料 Socket是通訊的端點,好比是電腦的網路介面卡,使得網路應用程式可以像介面卡插在主機板上一樣,插入網路中。一般說來你只會有一片網路卡在電腦中,但是你可以有許多sockets,而且它們也可以同時使用一片網路卡。用戶端與伺服器端都需要一個socket以存取網路資料,使用socket()函式呼叫就可開啟一個socket。(如圖一所示) 為Socket命名 伺服器端的程式必須為它的socket命名,這樣用戶端才能找到並正確地辨識出它的socket,如果伺服器沒有替它的socket命名,則協定堆疊會拒絕用戶端要通訊的請求。要幫socket取名必須設定三個參數:協定、連結埠號碼、及位址,而用戶端就要用這些值來和伺服器建立連結。要為socket命名,伺服器必須為socket位址結構設初始值並呼叫bind()函式,以指定本身連結埠號碼和IP位址,完成命名的工作。 與另一個Socket結合 假設我們在用戶端與伺服器端均開啟一個socket,並至少為伺服器端的socket命名。接下來伺服器要準備接收封包,而用戶端要準備發送封包,當此準備工作完成後,此兩端的sockets就叫建立一個”結合”(association)。如何為結合此兩端的socket做準備呢?在WinSock API中提供了幾個函式來完成此動作。在伺服器端則以呼叫listen()來準備接受用戶端送來的連結要求,如果收到連線要求,則開啟另一個新的socket來和用戶端進行連線(使用accept()函式);而在用戶端則是呼叫connect()函式與伺服器端的socket完成結合。 在Sockets間收送資料 此時我們已經在用戶端和伺服器的sockets間建立了結合,也就是說,我們已經可以開始收送資料了。如何收送資料呢?在一個已連結的socket上收送資料可呼叫recv()與send()來完成;而在一個無連結的socket上收送資料可呼叫recvfrom()與sendto()來完成。 關閉Socket 當用戶端完成收送資料且往後並不會在使用時,必須關閉socket,對TCP socket而言,關閉socket除了將socket的資源還給協定堆疊,此外並嘗試將以建立的連結關閉。但對UDP socket而言,則是單純地將資源還給協定堆疊。關閉socket可呼叫closesocket()來完成。  

Socket Read/Write Inside out User Space Server Client Server socket creation send data Client socket creation socket() bind() listen() write() accept() read() connect() sys_listen inet_listen sys_write do_sock_write sock_ sendmsg inet_ sendmsg tcp_ sendmsg tcp_ write_xmit sys_socket sock_create inet_create sys_bind inet_bind sys_accept inet_accept tcp_accept wait_for_ connection Kernel Space sys_read do_sock_read sock_ recvmsg sock_common_ recvmsg tcp_ recvmsg memcpy_ toiovec sys_connect inet_stream _connect tcp_v4_ getport tcp_v4_ connect inet_wait _connect sys_socketcall Internet The internals of the socket APIs used by simple TCP client-server programs in Linux are illustrated in Figure 5.40 . Programming APIs invoked from the user-space programs are translated into the sys_socketcall() kernel call and are then dispatched to their corresponding sys_*() calls. The sys_socket() (in net/socket.c ) calls sock_create() to allocate the socket and then calls inet_create() to initialize the sock structure according to the given parameters. The other sys_*() functions call their corresponding inet_*() functions because the sock structure is initialized to Internet address family ( AF_INET ). Since read() and write() in Figure 5.40 are not socket-specific APIs but are commonly used by file I/O operations, their call flows follow their inode operations in the file system to find that the given file descriptor is actually related to a sock structure. Subsequently they are translated into the corresponding do_sock_read() and do_sock_write() functions, and so on, which are socket-aware. In most UNIX systems the read()/write() functions are integrated into the Virtual File System (VFS). VFS is the software layer in the kernel that provides the file system interface to user space programs. It also provides an abstraction within the kernel which allows different file system implementations to coexist.

Socket Read/Write Inside out As shown in Figure 5.41 , the structure proto in the structure sock provides a list of function pointers that link to the necessary operations of a socket, such as connect , sendmsg , and recvmsg . By linking different sets of functions to the list, a socket can send or receive data over different protocols. Find out and read the function sets of other protocols such as UDP.

Performance Matters: Interrupt and Memory Copy at Socket Latency in receiving TCP segments in the TCP layer Receiving segments at a socket actually invokes two processing flows, as shown in the call graph of Figure 5.42 . The first flow starts from the system call, read() , later waits on the tcp_recvmsg() (for the case of TCP), which needs to be triggered by sk_data_ready() , and ends at the return to the user space. Thus, the time spent on this flow presents the user-perceived latency. The second flow starts from tcp_v4_rcv() (for the case of TCP) called by the IP layer with an incoming packet and ends at calling sk_data_ready() to trigger the resumption of first flow. Figure 5.42 shows the time spent on receiving TCP segments in the transport layer. tcp_recvmsg() takes the responsibility to copy data from the kernel structure into the user buffer, and therefore consumes the most time (2.6 μs). The system call, read() , spends time on mode switching between user and kernel modes. Besides, it also spends time on system table lookup. Therefore, read() spends significant time (2.4 μs). Finally, in the second flow, time spent on tcp_data_queue() and tcp_v4_rcv() are to queue and validate segments, respectively. Figure 5.43 shows the time spent in transmitting TCP segments. The top two most time-consuming functions are functionally similar to the ones in the receiving case. They are tcp_sendmsg() , which copies data from the user buffer to the kernel structure, and the system call write() , switching between user and kernel modes. After examining the time of both TCP segment transmission and reception, we can conclude that the bottlenecks of the TCP layer occur at two places: memory copy between the user buffer and the kernel structure, and switching between user and kernel modes Latency in transmitting TCP segments in the TCP layer

Open Source Implementation: Linux Socket Filter Linux Socket Filter (net/core/filter.c) Similar to BPF (Berkley Packet FIilter) network monitor rarpd filter buffer BPF protocol stack user kernel link-level driver network Figure 5.44 presents a layered model for packet capturing and filtering. The incoming packets are cloned from the normal protocol stack to the BPF, which then filters packets within the kernel level according the BPF instructions installed by the corresponding applications. Since only the packets passing through BPF will be directed to the user-space programs, the overhead of the data exchange between user and kernel spaces can be significantly reduced. To employ a Linux socket filter with a socket, the BPF instruction can be passed to the kernel by using the setsockopt() function implemented in socket.c , and setting the parameter optname to SO_ATTACH_FILTER . The function will assign the BPF instruction to the sock->sk_filter illustrated in Figure 5.41 . The BPF packet-filtering engine was written in a specific pseudo-machine code language inspired by Steve McCanne and Van Jacobson. BPF actually looks like a real assembly language with a couple of registers and a few instructions to load and store values and perform arithmetic operations and conditionally branch. The filter code examines each packet on the attached socket. The result of the filter processing is an integer that indicates how many bytes of the packet (if any) the socket should pass to the application level. This contributes to a further advantage that since often for the purpose of packet capturing and filtering we are interested in just the first few bytes of a packet, we can save processing time by not copying the excess bytes.