套接字编程--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是无链接的。可靠性并不可以保证