一、常用函數
1. socket()
int socket(int family, int type, int protocol);
socket()
打開一個網絡通訊端口,如果成功的話,返回一個文件描述符,應用程序可以像讀寫文件一樣用read/write
在網絡上收發數據,如果socket()
調用出錯則返回-1。對于IPv4,family
參數指定為AF_INET
。對于TCP協議,type
參數指定為SOCK_STREAM
,表示面向流的傳輸協議。如果是UDP協議,則type
參數指定為SOCK_DGRAM
,表示面向數據報的傳輸協議。protocol
參數的介紹從略,指定為0即可。
2. bind()
int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);
服務器程序所監聽的網絡地址和端口號通常是固定不變的,客戶端程序得知服務器程序的地址和端口號后就可以向服務器發起連接,因此服務器需要調用bind綁定一個固定的網絡地址和端口號。
bind()
成功返回0,失敗返回-1。bind()
的作用是將參數sockfd
和myaddr
綁定在一起,使sockfd
這個用于網絡通訊的文件描述符監聽myaddr
所描述的地址和端口號。前面講過,struct sockaddr *
是一個通用指針類型,myaddr
參數實際上可以接受多種協議的sockaddr
結構體,而它們的長度各不相同,所以需要第三個參數addrlen
指定結構體的長度
3. listen()
int listen(int sockfd, int backlog);// backlog取值0~5.
典型的服務器程序可以同時服務于多個客戶端,當有客戶端發起連接時,服務器調用的accept()
返回并接受這個連接,如果有大量的客戶端發起連接而服務器來不及處理,尚未accept
的客戶端就處于連接等待狀態,listen()
聲明sockfd
處于監聽狀態,并且最多允許有backlog
個客戶端處于連接待狀態,如果接收到更多的連接請求就忽略。listen()
成功返回0,失敗返回-1。
4. accept()
int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);
三方握手完成后,服務器調用accept()
接受連接,如果服務器調用accept()
時還沒有客戶端的連接請求,就阻塞等待直到有客戶端連接上來。cliaddr
是一個傳出參數,accept()
返回時傳出客戶端的地址和端口號。addrlen
參數是一個傳入傳出參數(value-result argument),傳入的是調用者提供的緩沖區cliaddr
的長度以避免緩沖區溢出問題,傳出的是客戶端地址結構體的實際長度(有可能沒有占滿調用者提供的緩沖區)。如果給cliaddr
參數傳NULL,表示不關心客戶端的地址。
二、簡單實現服務器編程(C語言)
unsigned char TcpRecvBuf[1520]; /* 接收緩沖區 */
static void Task_WebServer (void *pdata)
{
struct sockaddr_in server, client;
int sock, client_socket;
socklen_t len;
server.sin_family = AF_INET; /* 地址類型為IPv4 */
server.sin_port = htons( 80 ); /* 設置服務器的端口:80端口 */
server.sin_addr.s_addr = htonl( INADDR_ANY ); /* 監聽本地任意網卡 */
sock = socket( AF_INET, SOCK_STREAM, 0 ); /* 使用TCP連接 */
bind( sock, (struct sockaddr *)&server, sizeof( server ) );/* 綁定本地接口 */
listen( sock, 5 ); /* 進入監聽模式 */
while(1) {
len = sizeof(client);
client_socket = accept( sock, (struct sockaddr *)&client, &len );/* 接受一個連接,會阻塞程序 */
if(client_socket != -1) {
/*
* 接收數據,將會阻塞程序
*/
if ((read(client_socket, TcpRecvBuf, sizeof(TcpRecvBuf))) > 0) {
/*
* 簡單的檢查數據是否符合HTTP協議,數據內容開頭是“GET /”
*/
if(TcpRecvBuf[0] == 'G' && TcpRecvBuf[1] == 'E' &&
TcpRecvBuf[2] == 'T' && TcpRecvBuf[3] == ' ' &&
TcpRecvBuf[4] == '/') {
/**
* 下面為GET請求返回的數據,用戶可以自己定義
*/
//write(client_socket, http_html_hdr,sizeof(http_html_hdr));
//write(client_socket, indexdata,sizeof(indexdata));
}
}
close( client_socket ); /* 關閉此連接 */
}
/** 這里可以延時一定時間 */
}
}