Linux編程基礎——Socket編程

來源:互聯網
上載者:User

Linux下的Socket編程大體上包括Tcp Socket、Udp Socket即Raw Socket這三種,其中TCP和UDP方式的Socket編程用於編寫應用程式層的socket程式,是我們用得比較多的,而Raw Socket則用得相對較少,不在本文介紹範圍之列。

TCP Socket

基於TCP協議的用戶端/伺服器程式的一般流程一般如下:

它基本上可以分為三個部分:

一、建立串連:

  1. 伺服器調用socket()、bind()、listen()完成初始化後,調用accept()阻塞等待,處於監聽連接埠的狀態
  2. 用戶端調用socket()初始化後,調用connect()發出SYN段並阻塞等待伺服器應答
  3. 伺服器應答一個SYN-ACK段,用戶端收到後從connect()返回,同時應答一個ACK段,伺服器收到後從accept()返回。

二、傳輸資料:

建立串連後,TCP協議提供全雙工系統的通訊管道,伺服器端和用戶端根據協議可以通過read和write的反覆調用實現資料的傳輸

三、關閉串連:

當資料轉送已經完成後,伺服器和用戶端可以調用Close關閉串連,一端關閉串連後,另一端read函數則會返回0,可以根據這個特徵來感應另一端的退出。

下面就以一個簡單的EchoServer示範一下如何建立伺服器端和用戶端代碼,其中和socket相關api都會高亮顯示。

伺服器端樣本:

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

    #define MAXLINE 80
    #define SERV_PORT 8000

    int main(void)
    {
        char buf[MAXLINE];

        int listenfd = 0;
        listenfd = socket(AF_INET, SOCK_STREAM, 0);

        sockaddr_in servaddr = {0};
        servaddr.sin_family = AF_INET;
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        servaddr.sin_port = htons(SERV_PORT);

        bind(listenfd, (sockaddr *)&servaddr, sizeof(servaddr));
        listen(listenfd, 20);

        printf("Accepting connections ...\n");
        while (1)
        {
            sockaddr_in cliaddr = {0};
            socklen_t cliaddr_len = sizeof(cliaddr);
            int connfd = accept(listenfd, (sockaddr *)&cliaddr, &cliaddr_len);
    
            char str[INET_ADDRSTRLEN];
            printf("connected from %s at PORT %d\n",
                    inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
                    ntohs(cliaddr.sin_port));

            while(true)
            {
                int count = read(connfd, buf, MAXLINE);
                if (count == 0)
                    break;

                write(connfd, buf, count);
            }

            close(connfd);
            printf("closed from %s at PORT %d\n",
                    inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
                    ntohs(cliaddr.sin_port));
        }
    }

PS:這裡需要注意的一下的是sock函數的第二個參數SOCK_STREAM,它表示是一個TCP串連,後面我們會介紹通過傳入SOCK_DGRAM開啟udp串連。

伺服器端主體流程就是一個死迴圈,它接受一個socket串連,然後將其原封不動的返回給用戶端,待用戶端退出後,關閉socket串連,再次接受下一個socket串連。

用戶端代碼如下:

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

    #define MAXLINE 80
    #define SERV_PORT 8000
    #define MESSAGE "hello world"

    int main(int argc, char *argv[])
    {
        char buf[MAXLINE];

        int sockfd = socket(AF_INET, SOCK_STREAM, 0);

        sockaddr_in servaddr = {0};
        servaddr.sin_family = AF_INET;
        inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
        servaddr.sin_port = htons(SERV_PORT);

        if (0 != connect(sockfd, (sockaddr *)&servaddr, sizeof(servaddr)))
        {
            printf("connected failed");
            return 1;
        }

        write(sockfd, MESSAGE, sizeof(MESSAGE));
        int count = read(sockfd, buf, MAXLINE);

        printf("Response from server: %s\n",buf);

        close(sockfd);
        return 0;
    }

用戶端代碼比較簡單,這裡就不多介紹了。

UDP Socket

典型的UDP用戶端/伺服器通訊過程如所示:

由於UDP不需要維護串連,程式邏輯簡單了很多,但是UDP協議是不可靠的,實際上有很多保證通訊可靠性的機制需要在應用程式層實現,可能反而會需要更多代碼。

典型的樣本如下:

    /* server.cpp */
    #include
<stdio.h>
    #include
<string.h>
    #include
<netinet/in.h>
    #include
<arpa/inet.h>

    #define MAXLINE 80
    #define SERV_PORT 8000

    int main(void)
    {
        char buf[MAXLINE];
        char str[INET_ADDRSTRLEN];

        int sockfd = socket(AF_INET, SOCK_DGRAM, 0);

        sockaddr_in servaddr = {0};
        servaddr.sin_family = AF_INET;
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        servaddr.sin_port = htons(SERV_PORT);

        bind(sockfd, (sockaddr *)&servaddr, sizeof(servaddr));

        printf("Accepting connections ...\n");
        while (1)
        {
            sockaddr_in cliaddr;
            socklen_t cliaddr_len = sizeof(cliaddr);

            int count = recvfrom(sockfd, buf, MAXLINE, 0, (sockaddr *)&cliaddr, &cliaddr_len);
            if (count < 0)
            {
                printf("recvfrom error");
                continue;
            }

            printf("received from %s at PORT %d\n",
                 inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
                 ntohs(cliaddr.sin_port));

            sendto(sockfd, buf, count, 0, (sockaddr *)&cliaddr, sizeof(cliaddr));
        }
    }

    /* client.cpp */
    #include
<stdio.h>
    #include
<string.h>
    #include
<unistd.h>
    #include
<netinet/in.h>
    #include
<arpa/inet.h>

    #define MAXLINE 80
    #define SERV_PORT 8000

    int main(int argc, char *argv[])
    {
        char buf[MAXLINE];
        char str[INET_ADDRSTRLEN];
    
        int sockfd = socket(AF_INET, SOCK_DGRAM, 0);

        sockaddr_in servaddr = {0};
        servaddr.sin_family = AF_INET;
        inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
        servaddr.sin_port = htons(SERV_PORT);

        while (fgets(buf, MAXLINE, stdin) != NULL)
        {
            int count = sendto(sockfd, buf, strlen(buf), 0, (sockaddr *)&servaddr, sizeof(servaddr));
            if (count == -1)
            {
                printf("sendto error");
                return 0;
            }

            count = recvfrom(sockfd, buf, MAXLINE, 0, NULL, 0);
            if (count == -1)
            {
                printf("recvfrom error");
                return 0;
            }
    
            write(STDOUT_FILENO, buf, count);
        }

        close(sockfd);
        return 0;
    }

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.