本文編的是echo服務器示例程序,當收到客戶端的數據,服務器把數據不經加工地發送給客戶,采用TCP連接,采用端口8080進行設計,在整個過程中主要涉及socket的通信。
首先建立一個 socket.代碼如下:
int socketfd;
socketfd = socket(AF_INET, SOCK_STREAM, 0);
socket函數是我們寫socket程序遇到的第一個函數,它在指定的協議上創建一個socket,它的函數說明如下所示:
#include
int socket ( int AddressFamily, int Type, int Protocol)
其中:AddressFamily參數指定socket操作中所要解釋的網絡地址類型,值為如下之一:
AF_UNIX
表示操作系統文件路徑
AF_INET
表示Internet網絡地址
AF_NS
表示XEROX網絡地址
Type參數表明了通信的語義,即通信連接的方式。參數為如下之一:
SOCK_STREAM
提供穩定可靠的連接,并且是雙向的通信方式,如TCP。
SOCK_DGRAM
提供無連接的數據報通信,如UDP。
SOCK_RAW
提供該問內部網絡協議和網絡接口,只有root用戶才可以使用些協議。
返回值:成功則返socket描述符,出錯則返回-1,可通過errno代碼進行查看錯誤原因。
再次,把socket綁定到本機上,代碼如下:
- struct sockaddr_in sa;bzero(&sa, sizeof(sa));sa.sin_family = AF_INET;sa.sin_port = htons(EHCO_PORT);sa.sin_addr.s_addr = htons(INADDR_ANY);bzero(&(sa.sin_zero), 8);if(bind(socketfd, (struct sockaddr *)&sa, sizeof(sa))!= 0){printf("bind failed ");printf("errno=%d ", errno);exit(1);}else{printf("bind successfully ");}
上面的代碼中,定義一個scokaddr_in 結構體變量sa,然后填機服務所要開通的端口號和地址。
sa.sin_family = AF_INET;
>表明地址類型
sa.sin_port = htons(EHCO_PORT);
>端口號為8080
sa.sin_addr.s_addr = htons(INADDR_ANY);
>表明綁定在本機
然后利用bind函數,把剛才已建立的socket作為參數,綁定起來。
綁定完成后,服務器要偵聽客戶端的連接,因此首先要完成偵聽設置這一過程,由listen函數實現,代碼如下:
- if(listen(socketfd ,MAX_CLIENT_NUM) != 0)...{printf("listen error ");exit(1);}else...{printf("listen successfully ");}
listen(socketfd,MAX_CLIENT_NUM)表明在socketfd上偵聽,其中客戶個數最大值為MAX_CLIENT_NUM。
完成偵聽后,可以讓客戶與服務器進行連接了,服務想獲得客戶的請求,則需要通過 accept函數來獲得,同時,需要采用一個sockaddr_in結構體來獲得客戶的信息,代碼如下:
- int clientfd; struct sockaddr_in clientAdd;char buff[101];socklen_t len = sizeof(clientAdd);int closing =0;while( closing == 0 && (clientfd = accept(socketfd,
- (struct sockaddr *)&clientAdd, &len)) >0 ){int n;while((n = recv(clientfd,buff, 100,0 )) > 0){printf("number of receive bytes = %d ", n);write(STDOUT_FILENO, buff, n);send(clientfd, buff, n, 0);buff[n] = '';if(strcmp(buff, "quit ") == 0){break;}else if(strcmp(buff, "close ") == 0){//server closingclosing = 1;printf("server is closing ");break;}}close(clientfd);}
其中clientfd為客戶的socket,在服務器端,每接受一個客戶連接,都會返回一個客戶的socket描述符,服務器根據它與客戶進行通信。clientAdd為客戶地址信息的結構體,在accept函數中完成對它的填充,可依此得到客戶的地址信息。
- while( closing == 0 && (clientfd = accept(socketfd, (struct sockaddr *)&clientAdd, &len)) >0 )
等待第一個客戶,當第一個客戶的請求來到服務器后,該函數會返回,clientfd為客戶的socket描述符。
接著進行通信
while((n = recv(clientfd,buff, 100,0 )) > 0)
等待客戶的數據,收到數據后,在標準輸入出顯示接收的數據信息,并把它發送回給客戶:send(clientfd, buff, n, 0);
在這里,我們采用簡單的命令對通信進行控制,quit表示客戶要結束通信過程,而 close表示客戶請求關閉服務器,關閉只需使用 close函數即可完成。
下面是完整的代碼:
- #include #include #include #include #include #define EHCO_PORT 8080#define MAX_CLIENT_NUM 10int main(){int socketfd;socketfd = socket(AF_INET, SOCK_STREAM, 0);if(socketfd == -1){printf("errno=%d ", errno);exit(1);}else{printf("socket create successfully ");}struct sockaddr_in sa;bzero(&sa, sizeof(sa));sa.sin_family = AF_INET;sa.sin_port = htons(EHCO_PORT);sa.sin_addr.s_addr = htons(INADDR_ANY);bzero(&(sa.sin_zero), 8);if(bind(socketfd, (struct sockaddr *)&sa, sizeof(sa))!= 0){printf("bind failed ");printf("errno=%d ", errno);exit(1);}else{printf("bind successfully ");}//listenif(listen(socketfd ,MAX_CLIENT_NUM) != 0){printf("listen error ");exit(1);}else{printf("listen successfully ");}int clientfd;struct sockaddr_in clientAdd;char buff[101];socklen_t len = sizeof(clientAdd);int closing =0;while( closing == 0 && (clientfd = accept(socketfd, (struct sockaddr *)&clientAdd, &len)) >0 ){int n;while((n = recv(clientfd,buff, 100,0 )) > 0){printf("number of receive bytes = %d ", n);write(STDOUT_FILENO, buff, n);send(clientfd, buff, n, 0);buff[n] = '';if(strcmp(buff, "quit ") == 0){break;}else if(strcmp(buff, "close ") == 0){//server closingclosing = 1;printf("server is closing ");break;}}close(clientfd);}close(socketfd);return 0;}
經過cc編譯后,即可運行,在這里我們寫的程序是服務器程序,要想完成通信,也得寫一個客戶端程吧???
呵呵,我們先把客戶端的程序放下來,先測測我們服務器程序吧,在這里,我們使用 telnet充當客戶端進行測試,telnet可以說是一個很好的客戶端程序,呵呵:
本機IP為192.168.0.69,整個通信過程如下:
- linyongting@linyongting:~$ telnet 192.168.0.69 8080Trying 192.168.0.69...Connected to 192.168.0.69.Escape character is '^]'.hello! This is my first packet.Can you reply to me?hello! This is my first packet.Can you reply to me?Ohh, U did it!Ohh, U did it!see U next time!!!see U next time!!!quitquitConnection closed by foreign host.linyongting@linyongting:~$ telnet 192.168.0.69 8080Trying 192.168.0.69...Connected to 192.168.0.69.Escape character is '^]'.closecloseConnection closed by foreign host.
上面連接了兩次,第一次時,與服務器通信3次,每次發信息過去后,都收到與發出來一模一樣的信息。當用戶輸入quit的時候,服務端就會關閑與客戶通信的socket,通信結束。第二次客戶只輸入close,服務器響應后馬上關閉服務器,同時也關閉客戶端。下面是服務器的顯示內容:
- linyongting@linyongting:~/program/c$ ./echoServersocket create successfullybind successfullylisten successfully//第一次通信number of receive bytes = 53hello! This is my first packet.Can you reply to me?number of receive bytes = 16Ohh, U did it!number of receive bytes = 20see U next time!!!number of receive bytes = 6quit//第二次通信number of receive bytes = 7closeserver is closing
當客戶端輸入quit時,只是客戶端關閉,服務器還接著為其它客服端服務。當客戶端輸入 close時,服務關閉。
當前出現的問題:
我們的服務器序程只能與一個客戶端進行通信,只能當客戶端發出quit命令關閉后才能與下一個客戶端通信。
新聞熱點
疑難解答