1. 基本套接字函數
(1)socket函數原型
socket(建立一個socket文件描述符)
所需頭文件
#include <sys/types.h>
#include <sys/socket.h>
函數說明
建立一個socket文件描述符
函數原型
int socket(int domain, int type, int protocol)
函數傳入值
domain
AF_INET:IPv4協議
AF_INET6:IPv6協議
AF_LOCAL:Unix域協議
AF_ROUTE:路由套接口
AF_KEY:密鑰套接口
type
SOCKET_STREAM:雙向可靠數據流,對應TCP
SOCKET_DGRAM:雙向不可靠數據報,對應UDP
SOCKET_RAW:提供傳輸層以下的協議,可以訪問內部網絡接口,例如接收和發送ICMP報文
protocol
type為SOCKET_RAW時需要設置此值說明協議類型,其他類型設置為0即可
函數返回值
成功:socket文件描述符
失敗:-1,失敗原因存於error中
表18-1列出了當進行socket調用時,中協議簇(domain)與類型(type)可能產生的組合。
表18-1 socket中協議簇(domain)與類型(type)組合表
AF_INET
AF_INET6
AF_LOCAL
AF_ROUTE
AF_KEY
SOCK_STREAM
TCP
TCP
Yes
SOCK_DGRAM
UDP
UDP
Yes
SOCK_RAW
IPv4
IPv6
Yes
Yes
(2)bind函數原型
bind(將一個本地協議地址與socket文件描述符聯系起來)
所需頭文件
#include <sys/types.h>
#include <sys/socket.h>
函數說明
將一個協議地址與socket文件描述符聯系起來
函數原型
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
函數傳入值
sockfd
socket文件描述符
addr
my_addr指向sockaddr結構,該結構中包含IP地址和端口等信息
addrlen
sockaddr結構的大小,可設置為sizeof(struct sockaddr)
函數返回值
成功:0
失敗:-1,失敗原因存於error中
利用bind函數綁定地址時,可以指定IP地址和端口號,也可以指定其中之一,甚至一個也不指定。可以使用通配地址INADDR_ANY(為宏定義,其值等於0),它通知內核選擇IP地址。表18-2列出了設置socket地址結構的幾種方式,但在實際中,綁定的端口號都需要指定。
表18-2 設置socket地址結構的幾種方式
進程指定
說 明
IP地址
端口
通配地址INADDR_ANY
0
內核自動選擇IP地址和端口號
通配地址INADDR_ANY
非0
內核自動選擇IP地址,進程指定端口號
本地IP地址
0
進程指定IP地址,內核自動選擇端口號
本地IP地址
非0
進程指定IP地址和端口號
(3)listen函數原型
listen (等待連接)
所需頭文件
#include <sys/types.h>
#include <sys/socket.h>
函數說明
等待連接
函數原型
int listen(int sockfd, int backlog)
函數傳入值
sockfd
監聽socket文件描述符
backlog
套接字排隊的最大連接個數
函數返回值
成功:0
失敗:-1,失敗原因存於error中
特別說明
對於監聽socket文件描述符sockfd,內核要維護兩個隊列,分別為未完成連接隊列和已完成連接隊列,這兩個隊列之和不超過backlog
(4)connect函數原型
connect(建立socket連接)
所需頭文件
#include <sys/types.h>
#include <sys/socket.h>
函數說明
建立socket連接
函數原型
int connect(int sockfd, const struct sockaddr *serv_addr,
socklen_t addrlen)
函數傳入值
sockfd
socket文件描述符
serv_addr
連接的網絡地址和端口
addrlen
sockaddr結構的大小,可設置為sizeof(struct sockaddr)
函數返回值
成功:0
失敗:-1,失敗原因存於error中
附加說明
函數connect激發TCP的三路握手過程,出錯返回有以下幾種情況:
① 如果客戶沒有收到SYN分節的響應(總共75秒,這之間可能重發了若干次SYN),則返回ETIMEDOUT
② 如果對客戶的SYN的響應是RST,則表明該服務器主機在指定的端口上沒有進程在等待與之相連,函數返回錯誤ECONNREFUSED
③ 如果客戶發出的SYN在中間路由器上引發一個目的地不可達的ICMP錯誤,內核返回EHOSTUNREACH或ENETUNREACH錯誤(即ICMP錯誤)給進程
(5)accept函數原型
accept(接受socket連接)
所需頭文件
#include <sys/types.h>
#include <sys/socket.h>
函數說明
接受socket連接,返回一個新的socket文件描述符,原socket文件描述符仍為listen函數所用,而新的socket文件描述符用來處理連接的讀寫操作
函數原型
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
函數傳入參數
sockfd: socket文件描述符
addrlen:addr的大小,可設置為sizeof(struct sockaddr)
函數傳出參數
addr:填入遠程主機的地址數據
函數返回值
成功:實際讀取字節數
失敗:-1,錯誤代碼存放在error中
附加說明
① accept函數由TCP服務器調用,為阻塞函數,從已完成連接的隊列中返回一個連接;如果該對列為空,則進程進入阻塞等待
② 函數返回的套接字為已連接套接字,而監聽套接字仍為listen函數所用
(6)close函數原型
close (關閉連接的socket文件描述符)
所需頭文件
#include <unistd.h>
函數說明
關閉連接的socket文件描述符
函數原型
int close(int sockfd)
函數傳入值
sockfd:socket文件描述符
函數返回值
成功:0
失敗:-1,失敗原因存於error中
附加說明
① close函數默認功能是將套接字置為“已關閉”標記,並立即返回給進程,這個套接字不能再為該進程所用
② 正常情況下,close將引發四個分節終止序列,但在終止前將發送已排隊的數據
③ 如果套接字描述符訪問計數在調用close后大於0(多個進程共享同一個套接字的情況下),則不會引發TCP終止序列(即不會發送FIN分節)
(7)shutdown函數原型
shutdown(終止socket通信)
所需頭文件
#include <sys/socket.h>
函數說明
終止socket通信
函數原型
int shutdown(int s, int how)
函數傳入值
s
socket文件描述符
how
0(SHUT_RD):關閉socket連接的讀這一半,不再接收套接字中的數據且現留在收緩沖區的數據作廢
1(SHUT_WR):關閉socket連接的寫這一半(半關閉),但留在套接字發送緩沖區中的數據都會被發送,后跟TCP連接終止序列,不管訪問計數是否大於0,此后將不能再執行對套接字的任何寫操作
2(SHUT_RDWR):socket連接的讀、寫都關閉
函數返回值
成功:0
失敗:-1,失敗原因存於error中
(8)read函數原型
read(從打開的socket文件流中讀取數據)
所需頭文件
#include <unistd.h>
函數說明
從打開的socket文件流中讀取數據,這里僅說明此函數應用於socket的情況
函數原型
ssize_t read(int fd, void *buf ,size_t count)
函數傳入參數
fd: socket文件描述符
count:最大讀取字節數
函數傳出參數
buf:讀取數據的首地址
函數返回值
成功:實際讀取字節數
失敗:-1,錯誤代碼存放在error中
附加說明
調用函數read從socket文件流中讀取數據時,有如下幾種情況:
① 套接字接收緩沖區接收數據,返回接收到的字節數
② TCP協議收到FIN數據,返回0
③ TCP協議收到RST數據,返回-1,同時errno設置為ECONNRESET
④ 進程阻塞過程中接收到信號,返回-1,同時errno設置為EINTR
(9)write函數原型
write(向socket文件流中寫入數據)
所需頭文件
#include <unistd.h>
函數說明
向socket文件流中寫入數據,這里僅說明此函數應用於socket的情況
函數原型
ssize_t write (int fd,const void *buf,size_t count)
函數傳入參數
fd: socket文件描述符
buf:寫入數據的首地址
count:最大寫入字節數
函數返回值
成功:實際寫入的字節數
失敗:-1,錯誤代碼存放在error中
附加說明
調用函數write向socket文件流寫數據時,有如下幾種情況:
① 套接字發送緩沖區有足夠空間,返回發送的字節數
② TCP協議接收到RST數據,返回-1,同時errno設置為ECONNRESET
③ 進程阻塞過程中接收到信號,返回-1,同時errno設置為EINTR
2. 高級套接字函數
recv和send函數提供了和read和write差不多的功能。不過它們提供了第四個參數來控制讀寫操作。
(1) send函數原型
send(通過socket文件描述符發送數據到對方)
所需頭文件
#include <sys/types.h>
#include <sys/socket.h>
函數說明
通過socket文件描述符發送數據到對方
函數原型
ssize_t send(int s, const void *buf, size_t len, int flags)
函數傳入值
s
socket文件描述符
buf
發送數據的首地址
len
發送數據的長度
flags
0:此時功能同write,flags還可以設為以下標志的組合
MSG_OOB:發送帶外數據
MSG_DONTROUTE:告訴IP協議,目的主機在本地網絡,沒有必要查找路由表
MSG_DONTWAIT:設置為非阻塞操作
MSG_NOSIGNAL:表示發送動作不願被SIGPIPE信號中斷
函數返回值
成功:實際發送的字節數
失敗:-1,失敗原因存於error中
(2) recv函數原型
recv(通過socket文件描述符從對方接收數據)
所需頭文件
#include <sys/types.h>
#include <sys/socket.h>
函數說明
通過socket文件描述符從對方接收數據
函數原型
ssize_t recv(int s, void *buf, size_t len, int flags)
函數傳入值
s
socket文件描述符
len
可接收數據的最大長度
flags
0:此時功能同read,flags還可以設為以下標志的組合
MSG_OOB:接收帶外數據
MSG_PEEK:查看數據標志,返回的數據並不在系統中刪除,如果再次調用recv函數會返回相同的數據內容
MSG_DONTWAIT:設置為非阻塞操作
MSG_WAITALL:強迫接收到len大小的數據后才返回,除非有錯誤或有信號產生
函數傳出值
buf
接收數據的首地址
函數返回值
成功:實際發送的字節數
失敗:-1,失敗原因存於error中
3. 套接字屬性控制函數
系統提供getsockopt、setsockopt兩函數獲取和修改套接字結構中一些屬性,通過修改這些屬性,可以調整套接字的性能,進而調整應用程序的性能。
(1) getsockopt函數原型
getsockopt(獲取套接字的屬性)
所需頭文件
#include <sys/types.h>
#include <sys/socket.h>
函數說明
獲取套接字的屬性
函數原型
int getsockopt(int s, int level, int optname,
void *optval, socklen_t *optlen)
函數傳入值
s
socket文件描述符
level
SOL_SOCKET:通用套接字選項
IPPROTO_IP:IP選項
IPPROTO_TCP:TCP選項
optname
訪問的選項名,具體見表18-3
optlen
optval的長度
函數傳出值
optval
取得的屬性值
函數返回值
成功:0
失敗:-1,失敗原因存於error中
表18-3 套接字屬性表
level(級別)
optname(選項名
說明
數據類型
SOL_SOCKET
SO_BROADCAST
允許發送廣播數據
int
SO_DEBUG
允許調試
int
SO_DONTROUTE
不查找路由
int
SO_ERROR
獲得套接字錯誤
int
SO_KEEPALIVE
保持連接
int
SO_LINGER
延遲關閉連接
struct linger
SO_OOBINLINE
帶外數據放入正常數據流
int
SO_RCVBUF
接收緩沖區大小
int
SO_SNDBUF
發送緩沖區大小
int
SO_RCVLOWAT
接收緩沖區下限
int
SO_SNDLOWAT
發送緩沖區下限
int
SO_RCVTIMEO
接收超時
struct timeval
SO_SNDTIMEO
發送超時
struct timeval
SO_REUSERADDR
允許重用本地地址和端口
int
SO_TYPE
獲得套接字類型
int
SO_BSDCOMPAT
與BSD系統兼容
int
IPPROTO_IP
IP_HDRINCL
在數據包中包含IP首部
int
IP_OPTINOS
IP首部選項
int
IP_TOS
服務類型
int
IP_TTL
生存時間
int
IPPRO_TCP
TCP_MAXSEG
TCP最大數據段的大小
int
CP_NODELAY
不使用Nagle算法
int
(2)setsockopt函數原型
setsockopt(設置套接字的屬性)
所需頭文件
#include <sys/types.h>
#include <sys/socket.h>
函數說明
設置套接字的屬性
函數原型
int setsockopt(int s, int level, int optname,
const void *optval, socklen_t optlen)
函數傳入值
s
socket文件描述符
level
SOL_SOCKET:通用套接字選項
IPPROTO_IP:IP選項
IPPROTO_TCP:TCP選項
optname
設置的選項名,具體見表18-3
optval
設置的屬性值
optlen
optval的長度
函數返回值
成功:0
失敗:-1,失敗原因存於error中
(3)getsockopt、setsockopt函數舉例
sockopt.c源代碼如下:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
int main()
{
int sockfd,optval,optlen = sizeof(int);
int sndbuf = 0 ;
int rcvbuf = 0 ;
int flag;
if((sockfd = socket(AF_INET,SOCK_STREAM,0))<0)
{
perror("socket") ;
return -1 ;
}
getsockopt(sockfd,SOL_SOCKET,SO_TYPE,&optval,&optlen);
printf("optval = %d\n",optval);
optlen = sizeof(sndbuf);
flag = getsockopt(sockfd,SOL_SOCKET,SO_SNDBUF,&sndbuf,&optlen);
printf("sndbuf=%d\n",sndbuf) ;
printf("flag=%d\n",flag) ;
sndbuf = 51200;
flag = setsockopt(sockfd,SOL_SOCKET,SO_SNDBUF,&sndbuf, optlen);
sndbuf=0 ;
flag = getsockopt(sockfd,SOL_SOCKET,SO_SNDBUF,&sndbuf,&optlen);
printf("sndbuf=%d\n",sndbuf) ;
printf("flag=%d\n",flag) ;
close(sockfd);
return 0 ;
}
編譯 gcc sockopt.c -o sockopt。
執行 ./sockopt, 執行結果如下:
optval = 1
sndbuf=16384
flag=0
sndbuf=102400
flag=0
4. UDP讀寫函數
UDP套接字是無連接協議,必須使用sendto函數發送數據,必須使用recvfrom函數接收數據,發送時需指明目的地址。sendto函數與send功能基本相同,recvfrom與recv功能基本相同,只不過sendto函數和recvfrom函數參數中都帶有對方地址信息,這兩個函數是專門為UDP協議提供的。
(1)sendto函數原型
sendto(通過socket文件描述符發送數據到對方)
所需頭文件
#include <sys/types.h>
#include <sys/socket.h>
函數說明
通過socket文件描述符發送數據到對方,用於UDP協議
函數原型
ssize_t sendto(int s, const void *buf, size_t len, int flags,
const struct sockaddr *to, socklen_t tolen)
函數傳入值
s
socket文件描述符
buf
發送數據的首地址
len
發送數據的長度
flags
0:默認方式發送數據,flags還可以設為以下標志的組合
MSG_OOB:發送帶外數據
MSG_DONTROUTE:告訴IP協議,目的主機在本地網絡,沒有必要查找路由表
MSG_DONTWAIT:設置為非阻塞操作
MSG_NOSIGNAL:表示發送動作不願被SIGPIPE信號中斷
to
存放目的主機IP地址和端口信息
tolen
to的長度,可設置為sizeof(struct sockaddr)
函數返回值
成功:實際發送的字節數
失敗:-1,失敗原因存於error中
(2) recvfrom函數
recv(通過socket文件描述符從對方接收數據)
所需頭文件
#include <sys/types.h>
#include <sys/socket.h>
函數說明
通過socket文件描述符從對方接收數據,用於UDP協議
函數原型
ssize_t recvfrom(int s, void *buf, size_t len, int flags,
struct sockaddr *from, socklen_t *fromlen)
函數傳入值
s
socket文件描述符
len
可接收數據的最大長度
flags
0:默認方式接收數據,flags還可以設為以下標志的組合
MSG_OOB:接收帶外數據
MSG_PEEK:查看數據標志,返回的數據並不在系統中刪除,如果再次調用recv函數會返回相同的數據內容
MSG_DONTWAIT:設置為非阻塞操作
MSG_WAITALL:強迫接收到len大小的數據后才返回,除非有錯誤或有信號產生
fromlen
from的長度,可設置為sizeof(struct sockaddr)
函數傳出值
buf
接收數據的首地址
from
存放發送方的IP地址和端口
函數返回值
成功:實際發送的字節數
失敗:-1,失敗原因存於error中
---------------------