程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C >> 關於C >> 一起talk C栗子吧(第一百五十八回:C語言實例

一起talk C栗子吧(第一百五十八回:C語言實例

編輯:關於C

各位看官們,大家好,上一回中咱們說的是基於AF_UNIX域的數據報套接字通信的例子,這一回咱們說的例子是:基於AF_INET域的流套接字通信 。閒話休提,言歸正轉。讓我們一起talk C栗子吧!


看官們,我們在上一回中一起制作了我們的第二道佳肴是:基於AF_UNIX域的數據報套接字通信。今天,我將和大家一起制作第三道佳肴:基於AF_INET域的流套接字通信。

制作第三道佳肴的菜譜:流套接字過程。 制作第三道佳肴的食材:流套接字的接口,套接字屬性,套接字地址信息。

看官們,以上的內容,我們在前面章回中都詳細介紹過,如果大家忘記的話,可以參考前面的內容,重點是第一百四十七回的內容,因為這是我們的菜譜。在食材中最麻煩是套接字地址信息,大家可以參考一百五十五回中的例子。多說無益,我們通過具體的代碼來演示。

服務器端的通信過程及其代碼

//1.設置服務器端套接字的屬性:域,類型和協議,我們使用了getaddrinfo函數;
    char * host = "localhost";  //using localhost IP address:127.0.0.1
    char * server = "1080";     //using port 1080, it must be more then 1024
    struct addrinfo hints;
    struct addrinfo *result;

    memset(&hints,0,sizeof(struct addrinfo));
    result = NULL;

    hints.ai_flags = AI_NUMERICSERV;
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;

    //get address info ,it has all attribute of socket
    res = getaddrinfo(host,server,&hints,&result);
//2. 創建服務器端套接字
    server_fd = socket(result->ai_family,result->ai_socktype,result->ai_protocol);
//3.把服務器端的套接字和服務器的地址綁定在一起
    res = bind(server_fd,result->ai_addr,result->ai_addrlen);
//4.創建套接字隊列,為通信做好准備,開始監聽客戶端發來的通信連接請求
    res = listen(server_fd,2);
//5.接受客戶端發來的連接請求,並且獲得與客戶端匹配的socket
    client_fd = accept(server_fd,NULL,NULL);
//6.通過套接字讀取數據
    res = read(client_fd,buf,BUF_SIZE);
    printf("[server] receiving data (%s) from client by socket\n",buf);
//7.釋放套接字,關閉通信
    if(result->ai_next)
        freeaddrinfo(result);

    res = close(client_fd);
    res = close(server_fd);

客戶端的通信過程及其代碼

//1.設置客戶端套接字的屬性:域,類型和協議;
    char * host = "localhost";  //using localhost IP address:127.0.0.1
    char * server = "1080";     //using port 1080, it must be more then 1024
    struct addrinfo hints;
    struct addrinfo *result;

    memset(&hints,0,sizeof(struct addrinfo));
    result = NULL;

    hints.ai_flags = AI_NUMERICSERV;
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;

    //get address info ,it has all attribute of socket
    res = getaddrinfo(host,server,&hints,&result);
//2.創建客戶端套接字;
    client_fd = socket(result->ai_family,result->ai_socktype,result->ai_protocol);
//3.使用客戶端套接字和服務器進行連接;
    res = connect(client_fd,result->ai_addr,result->ai_addrlen);
//4.通過套接字發送數據;
    printf("[client] sending data (%s )to server by socket  \n",buf);
    res = write(client_fd,buf,sizeof(buf) );
//5.釋放套接字,斷開客戶端與服務器端的通信;
    if(result->ai_next)
        freeaddrinfo(result);

    res = close(client_fd);

看官們,以上是核心代碼,完整的代碼放到了我的資源中,大家可以下載使用。

關於上面的代碼,我做一些補充說明:

我們首先獲取套接字地址的信息,然後才創建套接字,雖然與菜譜中的順序不一致,但是這種做法是合理 的,因為我們以前創建套接字的時候,都是直接在函數中寫入套接字的屬性。在這裡,我們使用了getaddrinfo函數的結果,這種方法可以提高代碼的移植性。這種方法,也使用在了bind函數中。 我們在通信中使用了localhost主機,並且給它指定了端口號:1080。在指定端口號時,它的數值需要大於1024。因為Linux系統給小於1024的端口綁定了專門的服務。 在釋放套接字的同時,我們與要釋放存放套接字地址信息的鏈表。 與使用Unix域套接字通信的例子相比, 主要是設置套接字屬性和地址的方式不同,通信過程中讀取和接收數據的方式是相同的。

我們需要把服務器端的代碼和客戶端的代碼分別進行編譯,並且編譯成不同的可以執行文件:

$ gcc Ex092_InetStreamSocketClient.c -o client  //編譯客戶端
$ gcc Ex092_InetStreamSocketServer.c -o server  //編譯服務器端

看官們,美味佳肴做好了,我們一起來品嘗下,品嘗方法就是運行程序,下面是程序的運行結果,請大家參考:

$./server &             //在後面運行服務器
[1] 4643
$ ./client              //運行客戶端
please input less then 8 chars for using. 
hello
[client] sending data (hello )to server by socket  
[server] receiving data (hello) from client by socket
$ ./client               //再次運行客戶端
please input less then 8 chars for using. 
stream
[client] sending data (stream )to server by socket  
[server] receiving data (stream) from client by socket
[1]+  Done                    ./server          //服務器端運行結束

看官們,從上面的運行結果中可以看到,客戶端通過套接字發送數據給服務器,而服務器通過套接字接收客戶端發來的數據,這樣客戶端和服務器端可以通過套接字進行通信。另外,我們進行了兩次通信,通信的次數可以自己控制,甚至寫成無限次也是可以的。每次通信可以看作是一個完整的通信過程,我們在通信過程中發送的數據是字符串“hello”和”stream”,大家也可以發送其它的字符串。

各位看官,關於基於AF_INET域的流套接字通信的例子咱們就說到這裡。欲知後面還有什麼例子,且聽下回分解 。


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved