天天看點

網絡socket通訊原理socket網絡通信前言總結

socket網絡通信

打算要開啟apue這一個系列的專欄,即寫即更!!

第一講:socket網絡通訊原理

文章目錄

  • socket網絡通信
  • 前言
    • 一、檔案描述符是什麼?
    • 二、網絡socket通訊的流程
    • 1.伺服器端的邏輯流程
    • 2.用戶端的邏輯流程
    • 3.完整代碼如下
  • 總結

前言

提示:本文講述socket網絡通信的部分,其中包括的内容有:網絡socket通信的基本流程、涉及到的主要函數等等。

在本文内容學習之前需要了解的如下

一、檔案描述符是什麼?

檔案描述符(file descriptor)是核心為了高效管理已被打開的檔案所建立的索引,用于指代被打開的檔案,對檔案所有I/O操作相關的系統調用都需要通過檔案描述符。(如果前面的太書面不好了解就看這一句:檔案辨別符是唯一辨別一個檔案,友善對檔案進行操作的一個變量)

二、網絡socket通訊的流程

網絡socket通訊原理socket網絡通信前言總結

1.伺服器端的邏輯流程

Socket -> bind -> listen -> accept -> 進行正常的讀寫操作 -> close

“套接字API最初是作為UNIX作業系統的一部分而開發的,是以套接字API與系統的其它I/O裝置內建在一起。因為程式要為網際網路通信而建立一個套接字(socket)時,作業系統就傳回一個小整數作為描述符(descriptor)來表示這個套接字。然後應用程式以該描述符作為傳遞參數,通過調用相應函數(如read、write、close等)來完成某種操作(如從套接字中讀取或寫入資料)”,這就類似于檔案描述符的使用,隻是使用的對象不一樣。
1.是建立socket函數,對應于普通檔案的打開操作,用于建立一個socket描述字,唯一辨別一個socket。
2.當我們調用socket()函數建立一個socket辨別符時,傳回的socket描述字它存在于協定族(address family AF_XXX)空間中,但是沒有一個具體的位址,但沒有一個具體的位址,如果想要給它指派一個位址,就必須調用bind()函數,為socket綁定一個位址。
serv_addr.sin_family = AF_INET;
        serv_addr.sin_port = htons(LISTEN_PORT);
        serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

        if(bind(listen_fd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
        {
                printf("create socket failure: %s\n",strerror(errno));
                return -2;
        }
           
  1. socket()函數建立的socket預設是一個主動類型的,but作為一個伺服器,在調用socket()、bind()函數之後會調用listen()函數來監聽這個socket,使該函數變為被動類型的,等待用戶端的連接配接請求。
4.Tcp在調用前面三個函數以後,就會監聽指定了socket位址了。伺服器就會調用accept()來接受來自用戶端的請求,這個函數預設是一個阻塞函數,當有用戶端來連接配接的時候會調用connect()函數,沒有的話就會一直阻塞。

讀寫的操作在此略過

最後和檔案的讀寫一樣,有建立打開的操作就有關閉的操作,伺服器作為服務端一般是不關閉的,用戶端于伺服器端的資訊“交流”完畢之後,關閉的是用戶端。

2.用戶端的邏輯流程

Socket -> bind -> listen -> accept -> 一般的讀寫操作 -> close

在此隻談論伺服器端沒出現的connect()函數

Tcp用戶端調用socket()建立屬于socket的辨別符之後,就可以通過connect()函數來連接配接伺服器。用戶端使用這個函數表示發出連接配接請求,伺服器端會通過accept()函數來接受請求。

ps:一般在用戶端不使用bind()函數,而是在connect()時由系統随機生成一個,但是也可以bind一個位址和端口,即使用特定的IP和端口來連伺服器。(伺服器端需要bind是因為要有一個确切的位址和端口來提供服務,用戶端就不需要)

3.完整代碼如下

socket_server.c
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define LISTEN_PORT 8889
#define BACKLOG         13

int main()
{
        int rv = -1;
        int listen_fd,           client_fd = -1;
        struct sockaddr_in       serv_addr;
        struct sockaddr_in       cli_addr;
        socklen_t                cliaddr_len;
        char                     buf[1024];

        listen_fd = socket(AF_INET,SOCK_STREAM,0);
        if(listen_fd < 0)
        {
                printf("create socket failure: %s\n",strerror(errno));
                return -1;
        }
        printf("socket create fd[%d]\n",listen_fd);

        memset(&serv_addr,0,sizeof(serv_addr));
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_port = htons(LISTEN_PORT);
        serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

        if(bind(listen_fd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
        {
                printf("create socket failure: %s\n",strerror(errno));
                return -2;
        }
        printf("socket[%d] bind on port[%d] for all IP address ok\n",listen_fd,LISTEN_PORT);

        listen(listen_fd,BACKLOG);

        while(1)
        {
                printf("\n start waiting and accept new client connect...\n");
                client_fd = accept(listen_fd,(struct sockaddr*)&cli_addr,&cliaddr_len);

                if(client_fd < 0)
                {
                        printf("accept new socket failure:%s\n",strerror(errno));
                        return -2;
                }
                printf("accept new client[%s:%d] with fd [%d]\n",inet_ntoa(cli_addr.sin_addr),ntohs(cli_addr.sin_port),client_fd);


                memset(buf,0,sizeof(buf));
                if((rv = read(client_fd,buf,sizeof(buf))) < 0)
                {
                        printf("read data from client socket[%d] failure: %s\n",client_fd,strerror(errno));
                        close(client_fd);
                        continue;
                }
                else if(rv == 0)
                {
                        printf("client socket[%d] disconnnect\n",client_fd);
                        close(client_fd);
                        continue;
                }
                printf("read %d bytes data from client[%d] and echo it back: '%s'\n",rv,client_fd,buf);

                if(write(client_fd,buf,rv) < 0 )
                {
                        printf("write %d bytes data back to client[%d] failure: %s\n",rv,client_fd,strerror(errno));
                        close(client_fd);

                }
                sleep(1);
                close(client_fd);
        }
        close(client_fd);
}
           
socket_client.c
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define SERVER_IP  "127.0.0.1"
#define SERVER_PORT 8889
#define MSG_STR     "Hello, unix network program world!!"

int main()
{
        int                     conn_fd = -1;
        int                     rv = -1;
        char                    buf[1024];
        struct sockaddr_in      serv_addr;

        conn_fd = socket(AF_INET,SOCK_STREAM,0);
        if(conn_fd < 0)
        {
                printf("create socket failure%s\n",strerror(errno));
                return -1;
        }

        memset(&serv_addr,0,sizeof(serv_addr));
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_port = htons(SERVER_PORT);
        inet_aton(SERVER_IP,&serv_addr.sin_addr);

        if(connect(conn_fd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
        {
                printf("connect to server [%s:%d] failure: %s\n",SERVER_IP,SERVER_PORT,strerror(errno));
                return 0;
        }

        if(write(conn_fd,MSG_STR,strlen(MSG_STR)) < 0)
        {
                printf("write data to server [%s:%d] failure: %s\n",SERVER_IP,SERVER_PORT,strerror(errno));
                goto cleanup;
        }

        memset(buf,0,sizeof(buf));
        rv = read(conn_fd,buf,sizeof(buf));
        
        if(rv < 0)
        {
                printf("read data from server failure: %s\n",strerror(errno));
                goto cleanup;
        }
        else if(0 == rv)
        {
                printf("client connect to server get disconnected\n");
                goto cleanup;
        }
        printf("read %d bytes data from server:'%s'\n",rv,buf);

cleanup:
        close(conn_fd);

}
           

總結

這就是網絡socket通訊的流程,歡迎來信讨論,如有不對,感謝提醒。

繼續閱讀