套接字編程--TCP

1、socket編程編程

    socket自己有「插座「的意思,所以用來描述網絡鏈接的一對一關係。」在TCP/IP協議中,「TP地址+TCP或端口號」惟一標識網絡通信中的一個進程,「IP地址+端口號」就稱爲socket。(socket就像當於文件同樣,客戶端經過往裏面寫數據,服務器端就從裏面讀取數據,socket 就是用來作載體的)。爲TCP/TP協議設計的應用層編程接口稱爲socketAPI.服務器

2、網絡字節序網絡

    內存中的多字節數據相對於內存地址有大端和小端之分,磁盤文件中的多字節數據相對於文件中的偏移地址也有大端小端之分。網絡數據流一樣有大端小端之分,那麼如何定義網絡數據流的地址呢?發送主機一般將發送緩衝區中的數據按內存地址從低到高的順序發出,接收主機把從網絡上接到的字節依次保存在接收緩衝區中,也是按內存地址從低到高的順序保存,所以,網絡數據流的地址應這樣規定:先發出的數據是低地址,後發出的數據是高地址。TCP/IP協議規定,網絡數據流應採用大端字節序,(即低地址存放在高字節)    數據結構

    例如地址0-1是16位的源端口號,若是這個端口號是1000(0x3e8),則地址0是0x03,地址1是0xe8, 也就是先發0x03,再發0xe8,這16位在發送主機的緩衝區中也應該是低地址存0x03,高地址存0xe8。可是,若是發送主機是小端字節序的,這16位被解釋成0xe803,而不是1000。所以,發送主機把1000填到發送緩衝區以前須要作字節序的轉換。一樣地,接收主機若是是小端字節序的, 接到16位的源端口號也要作字節序的轉換。若是主機是大端字節序的,發送和接收都不須要作轉換。同理,32位的IP地址也要考慮網絡字節序和主機字節序的問題.socket

    爲使網絡程序具備可移植性,使一樣的C代碼在大端和小端計算機上編譯後都能正常運行,能夠調用如下庫函數作網絡字節序和主機字節序的轉換ide

    uint32_t htonl(uint32_t hostlong);
函數

    uint16_t htons(uint16_t hostshort);ui

    uint32_t ntohl(uint32_t netlong);spa

    uint16_t ntohs(uint16_t netshort);設計

*************** h表示host,n表示network,l表示long,s表示short.例如:htonl表示將32位的長整數從主機字節序轉換爲網絡字節序,******************       

3、socket地址的數據類型及其相關函數

    ①、 sockaddr數據結構

        一、struct sockaddr(這就至關於void*類型)

        二、struct sockaddr_in

            IPV4地址用 sockaddr_in結構體表示,包括16位端口號和32位IP 地址;IPV6地址用 sockaddr_in6結構體表示,包括16位端口號、128位IP地址和一些控制字段。

    ②、綁定函數(bind)

        綁定是將建立出來的socket和端口號綁定在一塊兒,是這個建立出來的socket監聽地址和端口號。

    ③、字符串轉in_addr的函數

        int inet_aton(const char* strptr,struct in_addr * addrptr);

        int_addr_t inet_addr(const char* strptr);//將點分十進制的IP地址轉換成32位的無符號×××

        int inet_pton(int family,const char* strptr,void* addrptr);

    ④、in_addr轉字符串的函數

        char* inet_ntoa(struct in_addr inaddr);//將×××轉換成點分十進制的IP地址

        const char* inet_ntop(int family,const void* addrptr,char * strptr,size_t len);       

     ⑤、監聽(listen)

        對於服務器端來講,須要一直保持一個監聽的狀態時刻監聽網絡中是否有鏈接請求,

    ⑥、接收(accept)

        對於服務器端,當有鏈接請求的時候,須要一個套接字用於處理請求。

    ⑦、鏈接(conncect)

        客戶端用於發送請求鏈接的函數

—————————————————————————————————————————————

用例子說明:

1、服務器端:

    ①、首先建立套接字

    ②、添加本地信息(struct sockaddr_in)

    ③、綁定端口號(bind)

    ④、服務器監聽是否有鏈接(listen)

    ⑤、接收穫取鏈接(accepet)

   #include<stdio.h>
   #include<stdlib.h>
   #include<sys/types.h>
   #include<sys/socket.h>
   #include<netinet/in.h>
   #include<arpa/ftp.h>
   #include<pthread.h>
   #include<string.h>
   static int start(char *_ip,int _port)
  {
      int listen_sock =socket(AF_INET,SOCK_STREAM,0);//建立套接字
      if(listen_sock < 0)
      {
          printf("socket");
          exit(1);
      }
      struct sockaddr_in local;//添加本地信息
      local.sin_family=AF_INET; //協議家族
      local.sin_port=htons(_port);//端口號
      local.sin_addr.s_addr=inet_addr(_ip);//IP地址
  
      if(bind(listen_sock ,(struct sockaddr *)&local,sizeof(local)) < 0)//綁定
      {
          printf("bind");
          exit(2);
      }
      if(listen(listen_sock ,5) < 0 )//監聽
      {
          perror("listen");
          exit(3);
      }
      return listen_sock ;
  
  }
  void usage(char *proc)
  {
      printf("usage :%s[ip][port]\n",proc);
  }
  int main(int argc,char * argv[])
  {
      if(argc != 3)
      {
          usage(argv[0]);
          exit(1);
      }
  
      int port= atoi(argv[2]);
      int sock=start(argv[1],port);
      struct sockaddr_in client;
      socklen_t len =sizeof(client);
      while(1)
      {
          int new_fd = accept(sock  ,(struct sockaddr*)&client,&len);
          if(new_fd <0)
          {
              printf("accept\n");
              continue;
          }
          printf("get aconnect... sock : %d,prot:%d ,ip:%s \n"
           ,new_fd,ntohs(client.sin_port),inet_ntoa(client.sin_addr));
 
          char buf[1024];
          while(1)
          {
              size_t size=read(new_fd,buf,sizeof(buf)-1);
            if(size > 0 )//read success
            {
               buf[size]='\0';
             }
            else if(size == 0)
            {
                printf("client close\n");
               break;
            }
           else
            {
                perror("read\n");
          }
            printf("client: %s \n",buf);
        }

2、客戶端

    ①、建立套接字

    ②、添加本地信息

    ③、創建鏈接

    ④、寫入數據進行發送

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<unistd.h>
  4 #include<stdlib.h>
  5 #include<sys/socket.h>
  6 #include<sys/types.h>
  7 #include<netinet/in.h>
  8 #include<error.h>
  9 #include<arpa/inet.h>
 10 void usage(char * _proc)
 11 {
 12     printf("usge:%s[remote ip]remote port[]\n",_proc);
 13 }
 14 int main(int argc,char* argv[])
 15 {
 16     if(argc !=3)
 17     {
 18         usage(argv[0]);
 19         exit(1);
 20     }
 21     int r_port=atoi(argv[2]);
 22     char* r_ip=argv[1];
 23 
 24     int sock = socket(AF_INET,SOCK_STREAM,0);//建立套接字
 25     if(sock < -1)
 26     {
 27         perror("sock");
 28         exit(1);
 29     }
 30     struct sockaddr_in  remote;//添加本地信息
 31     remote.sin_family = AF_INET;
 32     remote.sin_port= htons(r_port);
 33     remote.sin_addr.s_addr = inet_addr(r_ip);
 34 
 35     int ret=connect(sock,(struct sockaddr*)&remote,sizeof(remote));//創建鏈接
 36     if(ret<0)
 37     {
 38         printf("connetct\n");
 39     }
 40     char buf[1024];
 41     memset(buf,0,sizeof(buf));
 42     while(1)        
 43     {
 44         printf("please enter::");
 45         scanf("%s",&buf);
 46         write(sock,buf,sizeof(buf)-1);//寫入數據
 47     }
 48 
 49     return 0;
 50 }

結果以下:

    wKioL1dAB23wiJfmAAG8p6ll_No929.jpg總結:

    socket套接字編程簡單的來講就是建立一個公共的載體,客戶端能夠經過這個載體向服務器端發送數據,上面的這個程序,服務器一次只能接受一個客戶端的鏈接,效率是很低下的;TCP是面向鏈接的,可以保證信息的可靠性,而UDP是無鏈接的。可靠性並不可以保證

相關文章
相關標籤/搜索