Linux下的socket編程

server.cpp 是服務(wù)器端代碼,client.cpp 是客戶端代碼,要實現(xiàn)的功能是:客戶端從服務(wù)器讀取一個字符串并打印出來。

服務(wù)器端代碼 server.cpp:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main(){
    //創(chuàng)建套接字
    int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    //將套接字和IP、端口綁定
    struct sockaddr_in serv_addr;
    memset(&serv_addr, 0, sizeof(serv_addr));  //每個字節(jié)都用0填充
    serv_addr.sin_family = AF_INET;  //使用IPv4地址
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");  //具體的IP地址
    serv_addr.sin_port = htons(1234);  //端口
    bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));

    //進入監(jiān)聽狀態(tài),等待用戶發(fā)起請求
    listen(serv_sock, 20);

    //接收客戶端請求
    struct sockaddr_in clnt_addr;
    socklen_t clnt_addr_size = sizeof(clnt_addr);
    int clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);

    //向客戶端發(fā)送數(shù)據(jù)
    char str[] = "Hello World!";
    write(clnt_sock, str, sizeof(str));
   
    //關(guān)閉套接字
    close(clnt_sock);
    close(serv_sock);

    return 0;
}

客戶端代碼 client.cpp:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

int main(){
    //創(chuàng)建套接字
    int sock = socket(AF_INET, SOCK_STREAM, 0);

    //向服務(wù)器(特定的IP和端口)發(fā)起請求
    struct sockaddr_in serv_addr;
    memset(&serv_addr, 0, sizeof(serv_addr));  //每個字節(jié)都用0填充
    serv_addr.sin_family = AF_INET;  //使用IPv4地址
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");  //具體的IP地址
    serv_addr.sin_port = htons(1234);  //端口
    connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
   
    //讀取服務(wù)器傳回的數(shù)據(jù)
    char buffer[40];
    read(sock, buffer, sizeof(buffer)-1);
   
    printf("Message form server: %s\n", buffer);
   
    //關(guān)閉套接字
    close(sock);

    return 0;
}

先編譯 server.cpp 并運行:

[admin@localhost ~]$ g++ server.cpp -o server
[admin@localhost ~]$ ./server
|

正常情況下,程序運行到 accept() 函數(shù)就會被阻塞,等待客戶端發(fā)起請求。

接下來編譯 client.cpp 并運行:

[admin@localhost ~]$ g++ client.cpp -o client
[admin@localhost ~]$ ./client
Message form server: Hello World!
[admin@localhost ~]$

client 運行后,通過 connect() 函數(shù)向 server 發(fā)起請求,處于監(jiān)聽狀態(tài)的 server 被激活,執(zhí)行 accept() 函數(shù),接受客戶端的請求,然后執(zhí)行 write() 函數(shù)向 client 傳回數(shù)據(jù)。client 接收到傳回的數(shù)據(jù)后,connect() 就運行結(jié)束了,然后使用 read() 將數(shù)據(jù)讀取出來。

需要注意的是:

  1. server 只接受一次 client 請求,當 server 向 client 傳回數(shù)據(jù)后,程序就運行結(jié)束了。如果想再次接收到服務(wù)器的數(shù)據(jù),必須再次運行 server,所以這是一個非常簡陋的 socket 程序,不能夠一直接受客戶端的請求。

  2. 上面的源文件后綴為.cpp,是C++代碼,所以要用g++命令來編譯。

C++和C語言的一個重要區(qū)別是:在C語言中,變量必須在函數(shù)的開頭定義;而在C++中,變量可以在函數(shù)的任何地方定義,使用更加靈活。這里之所以使用C++代碼,是不希望在函數(shù)開頭堆砌過多變量。

源碼解析

  • 先說一下 server.cpp 中的代碼。

第11行通過 socket() 函數(shù)創(chuàng)建了一個套接字,參數(shù) AF_INET 表示使用 IPv4 地址,SOCK_STREAM 表示使用面向連接的數(shù)據(jù)傳輸方式,IPPROTO_TCP 表示使用 TCP 協(xié)議。在 Linux 中,socket 也是一種文件,有文件描述符,可以使用 write() / read() 函數(shù)進行 I/O 操作。

第19行通過 bind() 函數(shù)將套接字 serv_sock 與特定的IP地址和端口綁定,IP地址和端口都保存在 sockaddr_in 結(jié)構(gòu)體中。

socket() 函數(shù)確定了套接字的各種屬性,bind() 函數(shù)讓套接字與特定的IP地址和端口對應(yīng)起來,這樣客戶端才能連接到該套接字。

第22行讓套接字處于被動監(jiān)聽狀態(tài)。所謂被動監(jiān)聽,是指套接字一直處于“睡眠”中,直到客戶端發(fā)起請求才會被“喚醒”。

第27行的 accept() 函數(shù)用來接收客戶端的請求。程序一旦執(zhí)行到 accept() 就會被阻塞(暫停運行),直到客戶端發(fā)起請求。

第31行的 write() 函數(shù)用來向套接字文件中寫入數(shù)據(jù),也就是向客戶端發(fā)送數(shù)據(jù)。

和普通文件一樣,socket 在使用完畢后也要用 close() 關(guān)閉。

  • 再說一下 client.cpp 中的代碼。client.cpp 中的代碼和 server.cpp 中有一些區(qū)別。

第19行代碼通過 connect() 向服務(wù)器發(fā)起請求,服務(wù)器的IP地址和端口號保存在 sockaddr_in 結(jié)構(gòu)體中。直到服務(wù)器傳回數(shù)據(jù)后,connect() 才運行結(jié)束。

第23行代碼通過 read() 從套接字文件中讀取數(shù)據(jù)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Linux下的Socket編程(主要包括TCP部分) 轉(zhuǎn)載麻煩注明原文地址本文是Linux下基本的Socket編程...
    Bugfix閱讀 3,012評論 0 8
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,578評論 19 139
  • 簡介 Socket理論 Socket工作流程 核心函數(shù)講解 服務(wù)的如何獲取客戶端的信息 字符串ip和網(wǎng)絡(luò)二進制的轉(zhuǎn)...
    第八區(qū)閱讀 4,077評論 0 4
  • php 的 socket 編程算是比較難以理解的東西吧,不過,我們只要理解 socket 幾個函數(shù)之間的關(guān)系,以及...
    9ef822571b70閱讀 1,156評論 0 12
  • 誰家小灶又炊煙? 哪有山頭不雨逢。 撥云始知鯤鵬展, 忽而扶搖上九重。
    wildkid1024閱讀 295評論 0 0

友情鏈接更多精彩內(nèi)容