本文介紹在Linux使用者空間中,使用socket介面、收發雙線程管理緩衝隊列的例子。程式碼封裝含了以下要點:
1) 使用兩個線程管理收發隊列,為主函數提供專屬的收發介面;
2) 使用鎖,為並發資源即緩衝隊列提供互斥操作;
3) libevent/ select: 使用libevent或者select監視socket控制代碼,線程不阻塞;
4) socket:使用socket介面進行接收和發送。
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^分割線^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(一)socket的使用
Linux環境下一切皆檔案,socket即通訊端介面,調用socket()函數來獲得相應通訊端介面的檔案描述符。
包含標頭檔:
#include<sys/types.h>
#include<sys/socket.h>
函數原型:
int socket(int domain,int type,int protocol);
參數說明:
domain: 一般情況下設成AF_INET;
type:TCP串連用SOCK_STREAM, udp串連用SOCK_DGRAM,SOCK_RAW能到協議內部進行高效處理,SOCK_CONN_DGRAM是帶串連的資料報協議,目前只有ATM是支援的;
protocol:協議類型往往和具體的domain有關係,設為0自動選擇。
返回者為申請的socket介面描述符,如果失敗返回-1。
UDP傳輸:
1. 聲明並初始化本地和遠程sockaddr_in變數,設定本地ip和連接埠:
bzero(&serv_addr,sizeof(serv_addr));serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(serv_port);if(!strncmp(serv_ip,"AnyAddr",100))serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);elseserv_addr.sin_addr.s_addr = inet_addr(serv_ip);
以上代碼中,serv_ip可以是本機上任意地址,這種情況下設為 INADDR_ANY
bzero(&remote_addr,sizeof(remote_addr));remote_addr.sin_family = AF_INET;remote_addr.sin_port = htons(remote_port);remote_addr.sin_addr.s_addr = inet_addr(remote_ip);
UDP 的socket通訊端可以不調用connect()函數,目標地址可以在寫入的時候指定,因此可以使用一個通訊端向多個主機發送資料。
發送函數有:
write( )、send( )、sendto( ),在使用write( )和send( )時,必須先調用connect()繫結目標主機地址;
接收函數有: read( )、recv( )、recvfrom( ),在使用read( )和recv( )時,必須先調用connect()繫結目標主機地址,使用recvfrom(
),接收的時候同時獲得源地址和連接埠
注意,UDP的socket通訊端在調用connect()函數的時候,並沒有和遠程主機進行三向交握操作,這種有串連的udp通訊端可以避免沒有收到資料而導致的recvfrom()阻塞。
2. 綁定通訊端到本地地址,調用connect()函數建立“串連”
if(bind(serv_sockfd, (struct sockaddr *)&serv_addr, addrlen) == -1){perror("socket bind");return FALSE;}if(connect(serv_sockfd,(struct sockaddr *)& remote_addr,addrlen)== -1){ printf("connect error \n");}
綁定地址是必須的, 而對於udp傳輸來說,connect()函數不是必須的
3. 調用發送或者接收函數:
sendto(serv_sockfd,buffer_send,len,0,(struct sockaddr *)&remote_addr,addrlen);
說明: