1. 程式人生 > >c/c++ socket函數詳解

c/c++ socket函數詳解

astar 應該 type 表示 無法獲得 字節數 鏈接 .lib 隨機

c/c++ socket函數詳解

註意: 

使用socketAPI前,要先將相關鏈接庫(Ws2_32.lib)加入鏈接,並使用WSAStartUp函數初始化。
每個socket函數都可能失敗(返回-1),需要判斷結果

socket分成兩種:

  • 一種專門用來監聽新鏈接(或新活動),這種socket叫做master socket,一般只存在於服務器
  • 一種專門用來收發數據,這種socket叫做connected socket,客戶端和服務器都存在

int socket(int af,int type,int protocol);

  • // 建立一個socket用於連接
  • af:address family,如AF_INET
  • type:連接類型,通常是SOCK_STREAM或SOCK_DGRAM
  • protocol:協議類型,通常是IPPROTO_TCP或IPPROTO_UDP
  • // 返回值:socket的編號,為-1表示失敗

int bind(int socket,sockaddr * address,uint addrlen);

  • // 將一個地址和一個端口號綁定到一個socket連接上
  • // socket:之前創建的socket
  • // sockaddr:一個用來存放Ip地址和端口號的結構體
  • // addrlen:上述結構體的長度
  • // 返回值:為-1表示失敗,若端口被占用,會從新綁定一個隨機端口(仍返回失敗)
  • // 地址綁定為0表示綁定本機所有IP

int sendto(int socket,char * buf,uint buflen,int flag,sockaddr * address,uint addrlen);【僅UDP】

  • // 向一個指定的地址發送緩沖區內指定長度的消息
  • // socket:之前創建的socket
  • // buf:要發送的緩沖區
  • // buflen:要發送的長度
  • // flag:一般為0
  • // sockaddr:目標地址
  • // addrlen:上述結構體的長度
  • // 返回值:發送出去的長度

int recvfrom(int socket,char * buf,uint buflen,int flag,sockaddr * fromaddr,int * addrlen);

【阻塞】【僅UDP】

  • // 接收消息,可以獲取發送方的地址
  • // fromaddr:發送方地址(輸出參數)
  • // addrlen:發送方地址結構體的長度(輸入輸出參數)
  • // 返回值:>0表示收到的字節數,=0表示連接被關閉,-1表示出錯

int recv(int socket,char * buf,uint buflen,int flag);【阻塞】

  • // UDP時:接收任何一個發送到該socket的消息(無法獲取發送方地址)
  • // TCP時:接收一個已連接的socket (connected socket)發送的信息
  • // socket:UDP時,為之前創建的socket,TCP時,為connected socket
  • // buf:接收的緩沖區
  • // buflen:緩沖區的長度
  • // flag:一般為0
  • // 返回值:>0表示收到的字節數,=0表示連接被關閉,-1表示出錯
  • // 註意:對於TCP,請確保socket是已連接的,因為只有已連接的socket會阻塞此函數
  • // 該函數實際上是從緩沖區取指定長度的數據,如果緩沖區沒有數據,則會阻塞;如果沒有取完,則下次使用此函數的時候不會阻塞
  • // 應註意:當網速特別慢的時候,一次無法獲得對方發送的全部數據,在數據不完整的時候,程序可能無法向下執行,可以考慮將數據放在緩沖區中,等數據全部接收完成的時候再使用

int getsockname(int socket,sockaddr * address,int * addrlen);

  • // 獲取指定socket上綁定的IP、端口信息(不能獲取connected socket上的地址信息)
  • // address:socket上綁定的地址(輸出參數)
  • // addrlen:socket上綁定的地址結構體的長度(輸入輸出參數)

int getpeername(int socket,,sockaddr * address,int * addrlen);【僅TCP】

  • // 獲取一個已連接的socket的地址、端口信息
  • // 參數含義同上


struct sockaddr_in

  • 一個用來指定IP地址和端口號的結構體(不太好用,建議將其封裝)
    •   family // 即address family,如AF_INET
    •   port // 端口號(註意要按位倒序,使用htons函數)
    •   sin_addr.S_un.S_addr // 一個為long類型的ip地址
  • 該結構體所有成員的字序為網絡字序,低字節在前,高字節在後

int listen(int socket,int maxconn);【僅TCP】【服務器】

  • // 將一個socket設置為監聽狀態,專門用來監聽的socket叫做master socket
  • // maxconn:最大接收連接數
  • // 返回值:失敗返回-1,成功返回0

int accept(int socket,sockaddr * fromaddr,int * addrlen);【阻塞】【僅TCP】【服務器】

  • // 接收一個客戶機的連接,返回一個socket,來自客戶機的socket叫connected socket
  • // socket:用來監聽的socket(master socket)
  • // fromaddr:客戶機的地址信息
  • // addrlen:地址結構體的長度(輸入輸出參數)
  • // 返回值:返回一個新的socket,這個socket專門用來與此客戶機通訊(connected socket)

int connect(int socket,sockaddr * addr,int addrlen);【僅TCP】【客戶端】

  • // 使用當前socket連接一個地址(與服務器建立正式連接),此函數會觸發服務器端的accept、select函數
  • // 註意:服務端接收的socket值和客戶端socket值不一樣
  • // addr:一般是服務器地址

int send(int socket,char * buf,char buflen,int flag);【僅TCP】

  • // 向一個已連接的socket發送信息,這個socket應該是connected socket(非master socket)

int closesocket(int socket);

  • // 關閉一個已存在的socket【正常關閉】
  • // 失敗返回-1,成功返回0

UDP通訊流程

WSAStartup()
socket()
bind()
sendto(connected socket)/recv()/recvfrom()

TCP通訊流程(服務器):

WSAStartup()
socket()
bind()
listen()
accept()
send()/recv()

TCP通訊流程(客戶端):

WSAStartup()
socket()
bind()
connect()
send()/recv()

c/c++ socket函數詳解