Linux網絡編程
1 套接字地址結構
struct sockaddr{
unsigned short sa_family;//地址類型
char sa_data[14]; //14字節的地址協議}
sa_family表示套接字的協議族類型,對應於TCP/IP的協議該是AF_INET;
與該結構體等價的另一個數據結構:sockaddr_in。
struct sockaddr_in
{
unsigned short sin_family; //地址類型
unsigned short sin_port ; //端口號
struct in_addr sin_addr ;//IP地址
unsigned char sin_zero[8];//填充字節,一般爲0
}
struct in_addr {
unsigned long s_addr;
};
結構體sockaddr和結構體sockaddr_in都是16個字節。通常在編寫基於TCP/IP協議的網絡程序的時候,使用sockaddr_in來設置地址,然後通過類型的強制轉換成sockaddr類型。
struct sockaddr_in sock;
sock.sin_family = AF_INET;
sock.sin_port = htons(80);
sock.sin_addr.s_addr = inet_addr("202.112.12.11");
memset(sock.sin_zero, 0, sizeof(sock.sin_zero)); //將數組sin_zero設置成爲0
2 創建套接字
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
domain用來表示套接字所使用的協議族。AF_UNIX:在本機通訊的套接字;AF_INET:使用ipv4; AF_INET6:使用ipv6。
type指示套接字的類型。SOCK_STREAM SOCK_DGRAM SOCK_RAW
3 建立連接
函數connect用來在一個執行的套接字上穿件一個連接。
#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);
服務器的IP地址和端口號由serv_addr來制定。
4 綁定套接字
int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
這個函數只有服務器端使用。
5 在套接字上偵聽
int listen(int s, int backlog);
在服務器端,一般先創建一個socket,然後調用函數bind將該套接字綁定到某個端口上,接着調用listen函數等待來自於客戶端的連接請求。
一般多個客戶端連接到一個服務器,服務器設置一個連接隊列,記錄已經建立的連接,參數backlog指定了該連接隊列的最大長度。如果連接隊列已經達到最大,
之後的連接請求將會被服務器拒絕。
6 接受連接
int accept(int s, struct sockaddr *addr, socklen_t *addrlen);
參數s是由函數socket創建,經函數bind綁定到本地某一端口上,然後通過函數listen轉化而來的監聽套接字。
參數addr是用來保存發起連接請求的主機的地址和端口。
參數addrlen是addr所指向的結構體的大小。
只能對面向連接的套接字使用accept函數。accept成功時,將創建一個新的套接字,併爲這個新的套接字分配一個新的套接字描述符,類似文件描述符,進程可以利用這個新的套接字描述符與客戶端交換數據。參數S指定的套接字將繼續等待客戶端的連接請求。
如果參數s指向的套接字被設置成爲阻塞方式(Linux默認的設置),且連接請求隊列爲空的時候,則accept函數將被阻塞直到有連接請求爲止;
如果參數s指向的套接字被設置成爲非阻塞方式(fcntl),如果隊列爲空,則accept立即返回-1,errno設置成爲EAGAIN。
7 TCP套接字 發送數據
size_t send(int s, const void *msg, size_t len, int flags);
函數send只能對處於連接狀態的套傑斯使用。參數S爲已建立好連接的套接字描述符,即accept函數的返回值。
參數msg指向存放待發數據的緩衝區,參數len爲待發數據的長度。
如果要發送的數據太長而不能發送時,將出現錯誤,error設置成爲EMSGSIZE;
如果要發送的數據長度大於該套接字的緩衝區剩餘空間大小時,send()一般會被阻塞,如果該套接字設置成爲非阻塞方式,則此時立即返回-1.
執行成功則返回實際發送的數據的字節數。
執行成功只能說明數據寫入套接字的緩衝區中,並不表示數據已經成功的通過網絡發送到目的地。
8 接受數據
size_t recv(int s, coid *buf, size_t len, int flags);
如果一個數據包太長以至於緩衝區放不下的時候,剩餘部分的數據將可能被丟棄。
如果在指定的套接字上無數據到達時,recv函數將被阻塞,如果套接字設置成爲非阻塞的話,則立即返回-1;