① linux 進程間套接字通信(Socket)基礎知識
姓名:羅學元 學號:21181214375 學院:廣州研究院
【嵌牛導讀】Linux進程間套接字通信基礎
【嵌牛鼻子】Linux 進程間套接字及通信介紹
【嵌牛提問】Linux進程間套接字包含哪些內容,如何實現通信
一、套接字(Socket)通信原理
套接字通信允許互聯的位於不同計算機上的進程之間實現通信功能。
二、套接字的屬性
套接字的特性由3個屬性確定,它們分別是:域、類型和協議。
1. 套接字的域
它指定套接字通信中使用的網路介質,最常見的套接字域是AF_INET,它指的是Internet網路。當客戶使用套接字進行跨網路的連接時,它就需要用到伺服器計算機的IP地址和埠來指定一台聯網機器上的某個特定服務,所以在使用socket作為通信的終點,伺服器應用程序必須在開始通信之前綁定一個埠,伺服器在指定的埠等待客戶的連接。
另一個域AF_UNIX表示UNIX文件系統,就是文件輸入/輸出,它的地址就是文件名。
2. 套接字類型
網際網路提供了兩種通信機制:流(stream)和數據報(datagram),因而套接字的類型也就分為流套接字和數據報套接字。我們主要看流套接字。
流套接字由類型SOCK_STREAM指定,它們是在AF_INET域中通過TCP/IP連接實現,同時也是AF_UNIX中常用的套接字類型。
流套接字提供的是一個有序、可靠、雙向位元組流的連接,因此發送的數據可以確保不會丟失、重復或亂序到達,而且它還有一定的出錯後重新發送的機制。
與流套接字相對的是由類型SOCK_DGRAM指定的數據報套接字,它不需要建立連接和維持一個連接,它們在AF_INET中通常是通過UDP/IP實現的。它對可以發送的數據的長度有限制,數據報作為一個單獨的網路消息被傳輸,它可能丟失、復制或錯亂到達,UDP不是一個可靠的協議,但是它的速度比較高,因為它並不需要總是要建立和維持一個連接。
3.套接字協議
只要底層的傳輸機制允許不止一個協議來提供要求的套接字類型,我們就可以為套接字選擇一個特定的協議。通常只需要使用默認值。
三、套接字地址
每個套接字都有其自己的地址格式,對於AF_UNIX域套接字來說,它的地址由結構sockaddr_un來描述,該結構定義在頭文件
struct sockaddr_un{
sa_family_t sun_family; //AF_UNIX,它是一個短整型
char sum_path[]; //路徑名
};
對於AF_INET域套接字來說,它的地址結構由sockaddr_in來描述,它至少包括以下幾個成員:
struct sockaddr_in{
short int sin_family; //AN_INET
unsigned short int sin_port; //埠號
struct in_addr sin_addr; //IP地址
}
而in_addr被定義為:
struct in_addr{
unsigned long int s_addr;
}
四、基於流套接字的客戶/伺服器的工作流程
使用socket進行進程通信的進程採用的客戶/伺服器系統是如何工作的呢?
1.伺服器端
首先,伺服器應用程序用系統調用socket來創建一個套接字,它是系統分配給該伺服器進程的類似文件描述符的資源,它不能與其他的進程共享。
接下來,伺服器進程會給套接字起個名字,我們使用系統調用bind來給套接字命名。然後伺服器進程就開始等待客戶連接到這個套接字。
然後,系統調用listen來創建一個隊列,並將其用於存放來自客戶的進入連接。
最後,伺服器通過系統調用accept來接受客戶的連接。它會創建一個與原有的命名套接不同的新套接字,這個套接字只用於與這個特定客戶端進行通信,而命名套接字(即原先的套接字)則被保留下來繼續處理來自其他客戶的連接。
2.客戶端
基於socket的客戶端比伺服器端簡單。同樣,客戶應用程序首先調用socket來創建一個未命名的套接字,然後講伺服器的命名套接字作為一個地址來調用connect與伺服器建立連接。
一旦連接建立,我們就可以像使用底層的文件描述符那樣用套接字來實現雙向數據的通信。
② socket,linux用c語言實現
不難吧,我給你說下流程
客戶端
1、創建socket套接子s
2、用s連接到服務端,connect這個函數,成功返回0,錯誤 -1;
3、可以發送和接收數據,看你是面向連接還是無連接的了,具體的你自己處理
服務端
1、創建socket,比如s
2、綁定埠和本級IP。bind
3、listen。監聽埠
4、accept,接受服務端連接,如果成功的話會返回一個新套接字的,比如s1,你可以利用s1和客戶端進行通信,接收和發送和客戶端的一樣
還有需要提醒的是,你使用面向無連接的時候客戶端和服務端差不多是一樣的工作流程,都和上邊服務端工作模式一樣
③ 如何在linux上添加PHP的socket擴展
增大Linux的socket最大連接數
最近接的項目是模擬多個socket 客戶端與伺服器進行通信。由於Linux 系統的限制,在linux/include/linux/posix_types.h文件中有如下的宏定義:
#undef __FD_SETSIZE
#define __FD_SETSIZE 1024
這個宏是對最大文件描述符的定義為1024。當需要1024個以上的fd時,例如select()函數就會偵聽出錯。因此需要將1024改成需要的數目,但最多不能超過65535。但僅僅修改這個是不夠的。
第二步就需要修改一個進程最大打開的文件數。其具體步驟是:
1、cd /usr/src/linux-2.4/include/linux
2、vi limits.h編輯文件:
#define NR_OPEN 90240 原值為1024
#define OPEN_MAX 10240 原值為1024
3、vi fs.h
#define INR_OPEN 10240 原值為1024
#define NR_FILE 65536 原值為8192,這個值為內存64/1M的比率計算,1G內存計算為:64*1024
#define NR_RESERVED_FILES 128 原值為10.
4、cd /usr/src/linux-2.4/include/net
5、vi tcp.h
#define TCP_LHTABLE_SIZE 128 原值為32.便於listen偵聽隊列,設大。
設置最大打開文件數與內存相關,太大系統會變慢。
第三步就是編譯內核,其具體步驟是:
1. make clean
2. make
3. make dep
4. make bzImage
將bzImage 導入/boot 重啟系統即可!
用1024個以上客戶端與伺服器進行連接,在伺服器的終端用netstat |wc 命令可以統計出當前建立的socket的連接數。
④ linux手冊翻譯——socket(2)
socket - 創建一個用於通信的端點
socket() 創建用於通信的端點並返回引用該端點的文件描述符。 成功調用時返回的文件描述符,將是當前沒有被進程打開的所有文件描述符中編號最低的。
domain 參數指定一個通信域; 以決定用於通信的協議族。 這些系列在 <sys/socket.h> 中定義。 目前 Linux 內核理解的格式包括:
當然最常用的當然是 AF_INET ,即IPV4。
上述地址族的更多詳細信息以及其他幾個地址族的信息可以在 address_families(7) 中找到。
套接字具有指定的 type ,它指定了通信語義。 當前定義的類型有:
某些套接字類型可能不會被所有協議族實現。
從 Linux 2.6.27 開始,type 參數有第二個用途:除了指定套接字類型之外,它還可以包含以下任何值的按位或,以修改 socket() 的行為:
老朋友了,上述兩個,第一個是非阻塞,第二個是執行exec時自動關閉。
protocol 指定要與套接字一起使用的特定協議。 通常只存在一個協議來支持給定協議族中的特定套接字類型 ,在這種情況下,protocol 可以指定為 0。但是,可能存在許多協議,在這種情況下,必須在此指定特定協議方式。 特定協議對應的編號可以查看文件: /etc/protocols
SOCK_STREAM 類型的套接字是全雙工位元組流。 它們不保留記錄邊界。 流套接字必須處於連接狀態,然後才能在其上發送或接收任何數據。 到另一個套接字的連接是通過 connect(2) 調用創建的。 連接後,可以使用 read(2) 和 write(2) 調用或 其變體send(2) 和 recv(2) 的來傳輸數據。 當會話完成時,可以執行 close(2)。 帶外數據也可以按照 send(2) 中的描述進行傳輸,並按照 recv(2) 中的描述進行接收。
實現 SOCK_STREAM 的通信協議確保數據不會丟失或重復。 如果協議的緩沖空間中存在一條數據在合理的時間內不能成功傳輸,則認為該連接已失效。 當 SO_KEEPALIVE 在套接字上啟用時,將會以特定於協議的方式檢查另一端是否仍然存在。 如果進程在損壞的流上發送或接收,則會引發 SIGPIPE 信號; 這會導致不處理信號的進程退出。 SOCK_SEQPACKET 套接字使用與 SOCK_STREAM 套接字相同的系統調用。 唯一的區別是 read(2) 調用將只返回請求的數據量,到達數據包中剩餘的其他數據都將被丟棄。 傳入數據報中的所有消息邊界也被保留。
SOCK_DGRAM 和 SOCK_RAW 套接字允許將數據報發送到在 sendto(2) 調用中指定的通信者。 數據報通常用 recvfrom(2) 接收,它返回下一個數據報及其發送者的地址。
SOCK_PACKET 是一種過時的套接字類型,用於直接從設備驅動程序接收原始數據包。 改用 packet(7)。
An fcntl(2) F_SETOWN operation can be used to specify a process or process group to receive a SIGURG signal when the out-of-band data arrives or SIGPIPE signal when a SOCK_STREAM connection breaks unexpectedly. This operation may also be used to set the process or process group that receives the I/O and asynchronous notification of I/O events via SIGIO. Using F_SETOWN is equivalent to an ioctl(2) call with the FIOSETOWN or SIOCSPGRP argument.
When the network signals an error condition to the protocol mole (e.g., using an ICMP message for IP) the pending error flag is set for the socket. The next operation on this socket will return the error code of the pending error. For some protocols it is possible to enable a per-socket error queue to retrieve detailed information about the error; see IP_RECVERR in ip(7).
套接字的操作由套接字選項控制。 這些選項在 <sys/socket.h> 中定義。 函數setsockopt(2) 和getsockopt(2) 用於設置和獲取選項。對於選項的描述,詳見socket(7).
成功時,將返回新套接字的文件描述符。 出錯時,返回 -1,並設置 errno 以指示錯誤。
POSIX.1-2001, POSIX.1-2008, 4.4BSD.
The SOCK_NONBLOCK and SOCK_CLOEXEC flags are Linux-specific.
socket() appeared in 4.2BSD. It is generally portable to/from non-BSD systems supporting clones of the BSD socket layer (including System V variants).
在 4.x BSD 下用於協議族的清單常量是 PF_UNIX、PF_INET 等,而 AF_UNIX、AF_INET 等用於地址族。 但是,BSD 手冊頁已經承諾:「協議族通常與地址族相同」,隨後的標准到處都使用 AF_*。
⑤ linux手冊翻譯——socket(7)
socket - Linux 套接字介面
本手冊頁描述了 Linux 網路套接字層用戶介面。 套接字是用戶進程和內核中網路協議棧之間的統一介面。 協議模塊分為協議族(protocol families)(如 AF_INET、AF_IPX 和 AF_PACKET)和套接字類型(socket types)(如 SOCK_STREAM 或 SOCK_DGRAM)。 有關families和types的更多信息,請參閱 socket(2) 。
用戶進程使用這些函數來發送或接收數據包以及執行其他套接字操作。 有關更多信息,請參閱它們各自的手冊頁。
socket(2) 創建套接字,connect(2) 將套接字連接到遠程套接字地址,bind(2) 函數將套接字綁定到本地套接字地址,listen(2) 告訴套接字應接受新連接, accept(2) 用於獲取具有新傳入連接的新套接字。 socketpair(2) 返回兩個連接的匿名套接字(僅為少數本地families如 AF_UNIX 實現)
send(2)、sendto(2) 和sendmsg(2) 通過套接字發送數據,而recv(2)、recvfrom(2)、recvmsg(2) 從套接字接收數據。 poll(2) 和 select(2) 等待數據到達或准備好發送數據。 此外,還可以使用 write(2)、writev(2)、sendfile(2)、read(2) 和 readv(2) 等標准 I/O 操作來讀取和寫入數據。
getsockname(2) 返回本地套接字地址, getpeername(2) 返回遠程套接字地址。 getsockopt(2) 和 setsockopt(2) 用於設置或獲取套接字層或協議選項。 ioctl(2) 可用於設置或讀取一些其他選項。
close(2) 用於關閉套接字。 shutdown(2) 關閉全雙工套接字連接的一部分。
套接字不支持使用非零位置查找或調用 pread(2) 或 pwrite(2)。
通過使用 fcntl(2) 在套接字文件描述符上設置 O_NONBLOCK 標志,可以在套接字上執行非阻塞 I/O。 然後所有會阻塞的操作(通常)將返回 EAGAIN(操作應稍後重試); connect(2) 將返回 EINPROGRESS 錯誤。 然後用戶可以通過 poll(2) 或 select(2) 等待各種事件。
如果不使用poll(2) 和 select(2) ,還讓內核通過 SIGIO 信號通知應用程序有關事件的信息。 為此,必須通過 fcntl(2) 在套接字文件描述符上設置 O_ASYNC 標志,並且必須通過 sigaction(2) 安裝有效的 SIGIO 信號處理程序。 請參閱下面的信號討論。
每個套接字域(families)都有自己的套接字地址格式,具有特定於域的地址結構。 這些結構的首欄位都是整數類型的「家族」欄位(類型為 sa_family_t),即指出自己的套接字域或者說是protocol families。 這允許對所有套接字域可以使用統一的系統調用(例如,connect(2)、bind(2)、accept(2)、getsockname(2)、getpeername(2)),並通過套接字地址來確定特定的域。
為了允許將任何類型的套接字地址傳遞給套接字 API 中的介面,定義了類型 struct sockaddr。 這種類型的目的純粹是為了允許將特定於域的套接字地址類型轉換為「通用」類型,以避免編譯器在調用套接字 API 時發出有關類型不匹配的警告。
struct sockaddr 以及在AF_INET常用的地址結構struct sockaddr_in如下所示,sockaddr_in.sin_zero是佔位符:
此外,套接字 API 提供了數據類型 struct sockaddr_storage。 這種類型適合容納所有支持的特定於域的套接字地址結構; 它足夠大並且正確對齊。 (特別是它足夠大,可以容納 IPv6 套接字地址。)同struct sockaddr一樣,該結構體包括以下欄位,可用於標識實際存儲在結構體中的套接字地址的類型: sa_family_t ss_family;
sockaddr_storage 結構在必須以通用方式處理套接字地址的程序中很有用(例如,必須同時處理 IPv4 和 IPv6 套接字地址的程序)。
下面列出的套接字選項可以使用setsockopt(2) 設置並使用getsockopt(2) 讀取。
當寫入已關閉(由本地或遠程端)的面向連接的套接字時,SIGPIPE 被發送到寫入進程並返回 EPIPE。 當寫調用指定 MSG_NOSIGNAL 標志時,不發送信號。
當使用 FIOSETOWN fcntl(2) 或 SIOCSPGRP ioctl(2) 請求時,會在 I/O 事件發生時發送 SIGIO。 可以在信號處理程序中使用 poll(2) 或 select(2) 來找出事件發生在哪個套接字上。 另一種方法(在 Linux 2.2 中)是使用 F_SETSIG fcntl(2) 設置實時信號; 實時信號的處理程序將使用其 siginfo_t 的 si_fd 欄位中的文件描述符調用。 有關更多信息,請參閱 fcntl(2)。
在某些情況下(例如,多個進程訪問單個套接字),當進程對信號做出反應時,導致 SIGIO 的條件可能已經消失。 如果發生這種情況,進程應該再次等待,因為 Linux 稍後會重新發送信號。
核心套接字網路參數可以通過目錄 /proc/sys/net/core/ 中的文件訪問。
These operations can be accessed using ioctl(2):
error = ioctl(ip_socket, ioctl_type, &value_result);
Valid fcntl(2) operations:
Linux assumes that half of the send/receive buffer is used for internal kernel structures; thus the values in the corresponding /proc files are twice what can be observed on the wire. Linux will allow port reuse only with the SO_REUSEADDR option when this option was set both in the previous program that performed a bind(2) to the port and in the program that wants to reuse the port. This differs from some implementations (e.g., FreeBSD) where only the later program needs to set the SO_REUSEADDR option. Typically this difference is invisible, since, for example, a server program is designed to always set this option.
⑥ linux socket編程後是tcp還是udp
Linux socket編程既可以是TCP連接,也可以是UDP連接。Linux socket編程首先要用socket系統調用創建一個套接字,socket系統調用的原型是:
int socket(int domain, int type, int protocol);
當socket函數的type參數指定為SOCK_STREAM時,就相當於建立的是個TCP連接;當type參數指定為SOCK_DGRAM時,建立的就是一個UDP連接。當建立TCP或者UDP連接的時候,注意把第一個參數domain指定為AF_INET。