一赊颠、常用函數(shù)
1. socket()
int socket(int family, int type, int protocol);
socket()
打開一個網(wǎng)絡通訊端口舟铜,如果成功的話寸齐,返回一個文件描述符弛随,應用程序可以像讀寫文件一樣用read/write
在網(wǎng)絡上收發(fā)數(shù)據(jù),如果socket()
調(diào)用出錯則返回-1狱庇。對于IPv4惊畏,family
參數(shù)指定為AF_INET
。對于TCP協(xié)議密任,type
參數(shù)指定為SOCK_STREAM
颜启,表示面向流的傳輸協(xié)議。如果是UDP協(xié)議浪讳,則type
參數(shù)指定為SOCK_DGRAM
缰盏,表示面向數(shù)據(jù)報的傳輸協(xié)議。protocol
參數(shù)的介紹從略淹遵,指定為0即可口猜。
2. bind()
int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);
服務器程序所監(jiān)聽的網(wǎng)絡地址和端口號通常是固定不變的,客戶端程序得知服務器程序的地址和端口號后就可以向服務器發(fā)起連接合呐,因此服務器需要調(diào)用bind綁定一個固定的網(wǎng)絡地址和端口號暮的。
bind()
成功返回0笙以,失敗返回-1淌实。bind()
的作用是將參數(shù)sockfd
和myaddr
綁定在一起,使sockfd
這個用于網(wǎng)絡通訊的文件描述符監(jiān)聽myaddr
所描述的地址和端口號猖腕。前面講過拆祈,struct sockaddr *
是一個通用指針類型,myaddr
參數(shù)實際上可以接受多種協(xié)議的sockaddr
結(jié)構體倘感,而它們的長度各不相同放坏,所以需要第三個參數(shù)addrlen
指定結(jié)構體的長度
3. listen()
int listen(int sockfd, int backlog);// backlog取值0~5.
典型的服務器程序可以同時服務于多個客戶端,當有客戶端發(fā)起連接時老玛,服務器調(diào)用的accept()
返回并接受這個連接淤年,如果有大量的客戶端發(fā)起連接而服務器來不及處理,尚未accept
的客戶端就處于連接等待狀態(tài)蜡豹,listen()
聲明sockfd
處于監(jiān)聽狀態(tài)麸粮,并且最多允許有backlog
個客戶端處于連接待狀態(tài),如果接收到更多的連接請求就忽略镜廉。listen()
成功返回0弄诲,失敗返回-1。
4. accept()
int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);
三方握手完成后娇唯,服務器調(diào)用accept()
接受連接齐遵,如果服務器調(diào)用accept()
時還沒有客戶端的連接請求寂玲,就阻塞等待直到有客戶端連接上來。cliaddr
是一個傳出參數(shù)梗摇,accept()
返回時傳出客戶端的地址和端口號拓哟。addrlen
參數(shù)是一個傳入傳出參數(shù)(value-result argument),傳入的是調(diào)用者提供的緩沖區(qū)cliaddr
的長度以避免緩沖區(qū)溢出問題伶授,傳出的是客戶端地址結(jié)構體的實際長度(有可能沒有占滿調(diào)用者提供的緩沖區(qū))彰檬。如果給cliaddr
參數(shù)傳NULL,表示不關心客戶端的地址谎砾。
二逢倍、簡單實現(xiàn)服務器編程(C語言)
unsigned char TcpRecvBuf[1520]; /* 接收緩沖區(qū) */
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 ); /* 監(jiān)聽本地任意網(wǎng)卡 */
sock = socket( AF_INET, SOCK_STREAM, 0 ); /* 使用TCP連接 */
bind( sock, (struct sockaddr *)&server, sizeof( server ) );/* 綁定本地接口 */
listen( sock, 5 ); /* 進入監(jiān)聽模式 */
while(1) {
len = sizeof(client);
client_socket = accept( sock, (struct sockaddr *)&client, &len );/* 接受一個連接,會阻塞程序 */
if(client_socket != -1) {
/*
* 接收數(shù)據(jù)景图,將會阻塞程序
*/
if ((read(client_socket, TcpRecvBuf, sizeof(TcpRecvBuf))) > 0) {
/*
* 簡單的檢查數(shù)據(jù)是否符合HTTP協(xié)議较雕,數(shù)據(jù)內(nèi)容開頭是“GET /”
*/
if(TcpRecvBuf[0] == 'G' && TcpRecvBuf[1] == 'E' &&
TcpRecvBuf[2] == 'T' && TcpRecvBuf[3] == ' ' &&
TcpRecvBuf[4] == '/') {
/**
* 下面為GET請求返回的數(shù)據(jù),用戶可以自己定義
*/
//write(client_socket, http_html_hdr,sizeof(http_html_hdr));
//write(client_socket, indexdata,sizeof(indexdata));
}
}
close( client_socket ); /* 關閉此連接 */
}
/** 這里可以延時一定時間 */
}
}