網絡原理---socket入門

三、Socket編程

Socket接口是TCP/IP網絡的API,Socket接口定義了許多函數或例程,程序員可以用它們來開發TCP/IP網絡上的應用程序。要學Internet上的TCP/IP網絡編程,必須理解Socket接口。

Socket接口設計者最先是將接口放在Unix操作系統裏面的。如果瞭解Unix系統的輸入和輸出的話,就很容易瞭解Socket了。網絡的Socket數據傳輸是一種特殊的I/O,Socket也是一種文件描述符。Socket也具有一個類似於打開文件的函數調用Socket(),該函數返回一個整型的Socket描述符,隨後的連接建立、數據傳輸等操作都是通過該Socket實現的。

常用的Socket類型有兩種:流式Socket(SOCK_STREAM)和數據報式Socket(SOCK_DGRAM)。流式是一種面向連接的Socket,針對於面向連接的TCP服務應用;數據報式Socket是一種無連接的Socket,對應於無連接的UDP服務應用。

1、socket調用庫函數主要有:
創建套接字
Socket(af,type,protocol)
建立地址和套接字的聯繫
bind(sockid, local addr, addrlen)
服務器端偵聽客戶端的請求
listen( Sockid ,quenlen)
建立服務器/客戶端的連接 (面向連接TCP)
客戶端請求連接
Connect(sockid, destaddr, addrlen)
服務器端等待從編號爲Sockid的Socket上接收客戶連接請求
newsockid=accept(Sockid,Clientaddr, paddrlen)
發送/接收數據
面向連接:send(sockid, buff, bufflen)
recv( )
面向無連接:sendto(sockid,buff,…,addrlen)
recvfrom( )
釋放套接字
close(sockid)

2、TCP/IP應用編程接口(API)
服務器的工作流程:首先調用socket函數創建一個Socket,然後調用bind函數將其與本機地址以及一個本地端口號綁定,然後調用listen在相應的socket上監聽,當accpet接收到一個連接服務請求時,將生成一個新的socket。服務器顯示該客戶機的IP地址,並通過新的socket向客戶端發送字符串” hi,I am server!”。最後關閉該socket。

main()
{
    int sock_fd, client_fd;     /*sock_fd:監聽socket;client_fd:數據傳輸socket */
    struct sockaddr_in  ser_addr;               /* 本機地址信息 */
    struct sockaddr_in  cli_addr;               /* 客戶端地址信息 */
    char            msg[MAX_MSG_SIZE];      /* 緩衝區*/
    ser_sockfd = socket( AF_INET, SOCK_STREAM, 0 ); /*創建連接的SOCKET */
    if ( ser_sockfd < 0 )
    {                                               /*創建失敗 */
        fprintf( stderr, "socker Error:%sn", strerror( errno ) );
        exit( 1 );
    }
/* 初始化服務器地址*/
    addrlen = sizeof(struct sockaddr_in);
    bzero( &ser_addr, addrlen );
    ser_addr.sin_family     = AF_INET;
    ser_addr.sin_addr.s_addr    = htonl( INADDR_ANY );
    ser_addr.sin_port       = htons( SERVER_PORT );
    if ( bind( ser_sockfd, (struct sockaddr *) &ser_addr, sizeof(struct sockaddr_in) ) < 0 )
    {       /*綁定失敗 */
        fprintf( stderr, "Bind Error:%sn", strerror( errno ) );
        exit( 1 );
    }
/*偵聽客戶端請求*/
    if ( listen( ser_sockfd, BACKLOG ) < 0 )
    {
        fprintf( stderr, "Listen Error:%sn", strerror( errno ) );
        close( ser_sockfd );
        exit( 1 );
    }
    while ( 1 )
    {                                                       /* 等待接收客戶連接請求*/
        cli_sockfd = accept( ser_sockfd, (struct sockaddr *) &cli_addr, &addrlen );
        if ( cli_sockfd <= 0 )
        {
            fprintf( stderr, "Accept Error:%sn", strerror( errno ) );
        }else  { /*開始服務*/
            recv( cli_addr, msg, MAX_MSG_SIZE, 0 ); /* 接受數據*/
            printf( "received a connection from %sn", inet_ntoa( cli_addr.sin_addr ) );
            printf( "%sn", msg );                   /*在屏幕上打印出來 */
            strcpy( msg, "hi,I am server!" );
            send( cli_addr, msg, sizeof(msg), 0 );  /*發送的數據*/
            close( cli_addr );
        }
    }
    close( ser_sockfd );
}

客戶端的工作流程:首先調用socket函數創建一個Socket,然後調用bind函數將其與本機地址以及一個本地端口號綁定,請求連接服務器,通過新的socket向客戶端發送字符串” hi,I am client!”。最後關閉該socket。

main()
{
    int cli_sockfd;             /*客戶端SOCKET */
    int addrlen;
    char    seraddr[14];
    struct sockaddr_in  ser_addr,               /* 服務器的地址*/
                cli_addr;               /* 客戶端的地址*/
    char msg[MAX_MSG_SIZE];                         /* 緩衝區*/
    GetServerAddr( seraddr );
    cli_sockfd = socket( AF_INET, SOCK_STREAM, 0 ); /*創建連接的SOCKET */
    if ( ser_sockfd < 0 )
    {                                               /*創建失敗 */
        fprintf( stderr, "socker Error:%sn", strerror( errno ) );
        exit( 1 );
    }
/* 初始化客戶端地址*/
    addrlen = sizeof(struct sockaddr_in);
    bzero( &ser_addr, addrlen );
    cli_addr.sin_family     = AF_INET;
    cli_addr.sin_addr.s_addr    = htonl( INADDR_ANY );
    cli_addr.sin_port       = 0;
    if ( bind( cli_sockfd, (struct sockaddr *) &cli_addr, addrlen ) < 0 )
    {
/*棒定失敗 */
        fprintf( stderr, "Bind Error:%sn", strerror( errno ) );
        exit( 1 );
    }
/* 初始化服務器地址*/
    addrlen = sizeof(struct sockaddr_in);
    bzero( &ser_addr, addrlen );
    ser_addr.sin_family     = AF_INET;
    ser_addr.sin_addr.s_addr    = inet_addr( seraddr );
    ser_addr.sin_port       = htons( SERVER_PORT );
    if ( connect( cli_sockfd, (struct sockaddr *) &ser_addr, &addrlen ) != 0 ) /*請求連接*/
    {
/*連接失敗 */
        fprintf( stderr, "Connect Error:%sn", strerror( errno ) );
        close( cli_sockfd );
        exit( 1 );
    }
    strcpy( msg, "hi,I am client!" );
    send( sockfd, msg, sizeof(msg), 0 );    /*發送數據*/
    recv( sockfd, msg, MAX_MSG_SIZE, 0 );   /* 接受數據*/
    printf( "%sn", msg );                   /*在屏幕上打印出來 */
    close( cli_sockfd );
}

服務器的工作流程:首先調用socket函數創建一個Socket,然後調用bind函數將其與本機地址以及一個本地端口號綁定,接收到一個客戶端時,服務器顯示該客戶端的IP地址,並將字串返回給客戶端。

3、UDP/IP應用編程接口(API)

int main( int argc, char **argv )
{
    int ser_sockfd;
    int len;
/* int addrlen; */
    socklen_t       addrlen;
    char            seraddr[100];
    struct sockaddr_in  ser_addr;
/*建立socket*/
    ser_sockfd = socket( AF_INET, SOCK_DGRAM, 0 );
    if ( ser_sockfd < 0 )
    {
        printf( "I cannot socket successn" );
        return(1);
    }
/*填寫sockaddr_in 結構*/
    addrlen = sizeof(struct sockaddr_in);
    bzero( &ser_addr, addrlen );
    ser_addr.sin_family     = AF_INET;
    ser_addr.sin_addr.s_addr    = htonl( INADDR_ANY );
    ser_addr.sin_port       = htons( SERVER_PORT );


/*綁定客戶端
 * if(bind(ser_sockfd,(struct sockaddr *)&ser_addr,addrlen)<0)
 * {
 * printf("connect");
 * return 1;
 * }
 * while(1)
 * {
 * bzero(seraddr,sizeof(seraddr));
 * len=recvfrom(ser_sockfd,seraddr,sizeof(seraddr),0,(struct sockaddr*)&ser_addr,&addrlen);
 * /*顯示client端的網絡地址*/
    printf( "receive from %sn", inet_ntoa( ser_addr.sin_addr ) );
/*顯示客戶端發來的字串*/
    printf( "recevce:%s", seraddr );
/*將字串返回給client端*/
    sendto( ser_sockfd, seraddr, len, 0, (struct sockaddr *) &ser_addr, addrlen );
}

客戶端的工作流程:首先調用socket函數創建一個Socket,填寫服務器地址及端口號,從標準輸入設備中取得字符串,將字符串傳送給服務器端,並接收服務器端返回的字符串。最後關閉該socket。

int GetServerAddr( char * addrname )
{
    printf( "please input server addr:" );
    scanf( "%s", addrname );
    return(1);
}


int main( int argc, char **argv )
{
    int         cli_sockfd;
    int         len;
    socklen_t       addrlen;
    char            seraddr[14];
    struct sockaddr_in  cli_addr;
    char            buffer[256];
    GetServerAddr( seraddr );
/* 建立socket*/
    cli_sockfd = socket( AF_INET, SOCK_DGRAM, 0 );
    if ( cli_sockfd < 0 )
    {
        printf( "I cannot socket successn" );
        return(1);
    }
/* 填寫sockaddr_in*/
    addrlen = sizeof(struct sockaddr_in);
    bzero( &cli_addr, addrlen );
    cli_addr.sin_family     = AF_INET;
    cli_addr.sin_addr.s_addr    = inet_addr( seraddr );
/* cli_addr.sin_addr.s_addr=htonl(INADDR_ANY); */
    cli_addr.sin_port = htons( SERVER_PORT );
    bzero( buffer, sizeof(buffer) );
/* 從標準輸入設備取得字符串*/
    len = read( STDIN_FILENO, buffer, sizeof(buffer) );
/* 將字符串傳送給server端*/
    sendto( cli_sockfd, buffer, len, 0, (struct sockaddr *) &cli_addr, addrlen );
/* 接收server端返回的字符串*/
    len = recvfrom( cli_sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *) &cli_addr, &addrlen );
/* printf("receive from %sn",inet_ntoa(cli_addr.sin_addr)); */

    printf( "receive: %s", buffer );
    close( cli_sockfd );
}

這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章