Linux C socket 編程之TCP

本文主要是,簡單實現tcp鏈接的兩個程序。本文編寫,假設讀者有socket 編程思想。熟悉C編程。編程

服務端:數組


#include <stdio.h>
#include <stdlib.h>

#include <sys/socket.h>
#include <netinet/in.h> //互聯網地址族
#include <arpa/inet.h>
#include <netdb.h>

#include <ctype.h> //toupper (小寫轉化爲大寫)

int port =8000;

/*服務端*/
int main(int argc, char** argv) {

    struct sockaddr_in sin;//struct sockaddr和struct sockaddr_in這兩個結構體用來處理網絡通訊的地址。
    struct sockaddr_in pin;
    int sock_descriptor;//  套接口描述字
    int temp_sock_descriptor;
    int address_size;
    char buf[16384];// 緩衝區大小

    int i,len;

    /*
     *int socket(int domain, int type, int protocol);
     * PF_INET, AF_INET: Ipv4網絡協議
     * PF_INET6, AF_INET6: Ipv6網絡協議。
     * type參數的做用是設置通訊的協議類型,可能的取值以下所示:
        SOCK_STREAM: 提供面向鏈接的穩定數據傳輸,即TCP協議。
        OOB: 在全部數據傳送前必須使用connect()來創建鏈接狀態。
        SOCK_DGRAM: 使用不連續不可靠的數據包鏈接。
        SOCK_SEQPACKET: 提供連續可靠的數據包鏈接。
        SOCK_RAW: 提供原始網絡協議存取。
        SOCK_RDM: 提供可靠的數據包鏈接。
        SOCK_PACKET: 與網絡驅動程序直接通訊。
     */
    //socket函數,向系統申請一個通訊端口
    sock_descriptor=socket(AF_INET,SOCK_STREAM,0);//IPV4 TCP協議
    if(sock_descriptor== -1)//申請失敗
    {
        perror("call to socket");
        exit(1);
    }

    bzero(&sin,sizeof(sin));// 初始化 而後是設置套接字
    sin.sin_family = AF_INET;//協議族,在socket編程中只能是AF_INET(TCP/IP協議族)
    sin.sin_addr.s_addr=INADDR_ANY;//sin_addr存儲IP地址,使用in_addr這個數據結構
                                  //s_addr按照網絡字節順序存儲IP地址
                                   //in_addr32位的IPv4地址
    sin.sin_port=htons(port);//存儲端口號

      //將套接字(sin) 跟端口(sock_descriptor)連接
    if(bind(sock_descriptor,(struct sockaddr *)&sin,sizeof(sin)) ==-1)
    {
        perror("call to bind");
        exit(1);
    }
    /*int PASCAL FAR listen( SOCKET s, int backlog);
       S:用於標識一個已捆綁未鏈接套接口的描述字。
       backlog:等待鏈接隊列的最大長度。
     * listen()僅適用於支持鏈接的套接口,如SOCK_STREAM類型的。
     */
    if(listen(sock_descriptor,20) == -1) //在端口sock_descriptor監聽
    {
        perror("call to listen");
        exit(1);
    }

    printf("accepting connections \n");

    while(1)
    {   //用來監聽的端口sock_descriptor
        temp_sock_descriptor = accept(sock_descriptor,(struct sockaddr *)&pin, &address_size);
        if(temp_sock_descriptor== -1)
        {
           perror("call to accept");
           exit(1);
        }

        /*int PASCAL FAR recv( SOCKET s, char FAR* buf, int len, int flags);
          s:一個標識已鏈接套接口的描述字。
          buf:用於接收數據的緩衝區。
          len:緩衝區長度。
          flags:指定調用方式。
         */

        if(recv(temp_sock_descriptor,buf,16384,0) ==-1)
        {
            perror("call to recv");
            exit(1);
        }

        printf("received from client:%s\n",buf);

        len =strlen(buf);
        for(i=0;i<len;i++)
        {
            buf[i]= toupper(buf[i]);//將小寫字母轉化爲大寫字母
        }
        /*int PASCAL FAR send( SOCKET s, const char FAR* buf, int len, int flags);
          s:一個用於標識已鏈接套接口的描述字。
          buf:包含待發送數據的緩衝區。
          len:緩衝區中數據的長度。
          flags:調用執行方式。*/
        
        /*send()   基於連接的發送 TCP
         *sendto() 基於無連接到   UDP
         */
        
        if(send(temp_sock_descriptor,buf,len,0) == -1)
        {
            perror("call to send");
            exit(1);
        }

        close(temp_sock_descriptor);

    }

    return (EXIT_SUCCESS);
}網絡

客戶端:數據結構

#include <stdio.h>
#include <stdlib.h>

#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
/*客戶端*/
char *host_name ="127.0.0.1";//須要搜尋服務端IP地址
int port = 8000;

/*argc: 整數,用來統計你運行程序時送給main函數的命令行參數的個數
 * argv: 字符串數組,用來存放指向你的字符串參數的指針數組,每個元素指向一個參數
  argv[0] 指向程序運行的全路徑名
  argv[1] 指向在DOS命令行中執行程序名後的第一個字符串
  argv[2] 指向執行程序名後的第二個字符串
   */
int main(int argc, char** argv) {
    char buf[8192];
    char message[256];
    int socket_descriptor;
    struct sockaddr_in pin;//處理網絡通訊的地址
    /*
     * hostent記錄主機的信息,包括主機名、別名、地址類型、地址長度和地址列表
     * struct hostent {
         char *h_name;地址的正式名稱
         char **h_aliases;空字節-地址的預備名稱的指針
         int h_addrtype;地址類型; 一般是AF_INET。
         int h_length;地址的比特長度。
         char **h_addr_list;零字節-主機網絡地址指針。網絡字節順序。
      };
     #define h_addr h_addr_list[0] //h_addr_list中的第一地址
     */
    struct hostent *server_host_name;

    char *str = "A default test string";

    if(argc<2)//運行程序時送給main函數到命令行參數個數
    {
        printf("Usage:test \"Any test string\"\n");
        printf("we will send a default test string. \n");
    }
    else
    {
        str =argv[1];
    }
    /*
     * gethostbyname()返回對應於給定主機名的包含主機名字和地址信息的
     * hostent結構指針。結構的聲明與gethostaddr()中一致。*/
    if((server_host_name = gethostbyname(host_name))==0)
    {
        perror("Error resolving local host \n");
        exit(1);
    }

    bzero(&pin,sizeof(pin));
    pin.sin_family =AF_INET;
                          //htonl()將主機的無符號長整形數轉換成網絡字節順序
    pin.sin_addr.s_addr=htonl(INADDR_ANY);//s_addr按照網絡字節順序存儲IP地址
                      //in_addr 32位的IPv4地址  h_addr_list中的第一地址
    pin.sin_addr.s_addr=((struct in_addr *)(server_host_name->h_addr))->s_addr;// 跟書上不同 必須是h_addr

    pin.sin_port=htons(port);
    /*申請一個通訊端口*/
    if((socket_descriptor =socket(AF_INET,SOCK_STREAM,0))==-1)
    {
        perror("Error opening socket \n");
        exit(1);
    }
     //pin 定義跟服務端鏈接的 IP 端口
    if(connect(socket_descriptor,(void *)&pin,sizeof(pin))==-1)
    {
        perror("Error connecting to socket \n"); ////
        exit(1);
    }
    printf("Sending message %s to server \n",str);

    if(send(socket_descriptor,str,strlen(str),0) == -1)
    {
        perror("Error in send\n");
        exit(1);
    }

    printf("..sent message.. wait for response...\n");

    if(recv(socket_descriptor,buf,8192,0) == -1)
    {
        perror("Error in receiving response from server \n");
        exit(1);
    }

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

    close(socket_descriptor);

    return (EXIT_SUCCESS);
}dom

相關文章
相關標籤/搜索