[Linux程序设计笔记]14章:套接字Socket

 

A 套接字:socket用于本机的两个程序通讯或者两个在不同机器上的进程通讯。

   1.创建套接字

        int socket(int domian, int type, int protocol);
       
        头文件:#include<sys/types.h>
               #include<sys/socket.h>
     
        domian  : 域,包括AF_INET(因特网),AF_UNIX(Unix本机),AF_ISO,AF_NS,AF_IPX,AF_APPLETALK。
                  主要使用AF_INET, AF_UNIX.
                  可以使用AF_UNIX创建socket文件,来完成两个进程的本地通讯。此时两个进程要约定同一个socket文件通讯,
                  正如使用管道一样(可以看到在那个目录下生成了socket文件)。
        type    :类型,SOCK_STREAM(TCP)和SOCK_DGRAM(UDP)。(好像至少在windows中还有SOCK_RAW,原始套接字,比如用于检测网络)
        protocol:协议,一般为默认0。

       socket返回一个文件描述符,当这个套接字和通信线路另一端的套接字连接好之后,可以用read和write进行收发。用close进行关闭。
   
   2.绑定套接字(命名套接字)
      
        int bind(int socket, const struct sockaddr * address, size_t address_len);
  
        #include<sys/socket.h>
       
        地址:对于AF_UNIX的地址是sockaddr_un。
                   其结构为:struct sockaddr_un
                            {
                                sa_family_t sun_family;   /*AF_UNIX*/
                                char        sun_path[];   /*pathname*/
                            };
              对于AF_INET的地址是sockaddr_in。
                    其结构为: struct sockaddr_in
                             {
                                 short    int           sin_family;     /*AF_INET*/
                                 unsigned short int     sin_port;       /*port number*/
                                 struct in_addr         sin_addr;       /*Internet address*/
                              };  
                     其中struct in_addr{
                         unsigned long int s_addr;
                         }
                      这是一个32位的二进制数字。
               注意:
                  (1)此时需要进行字节序的装换,分别是htonl,htons,ntohl,ntohs.
                       如端口号的赋值:address.sin_port=htons(9734);
                  (2)用点分十进制的方式进行IP地址赋值的时候要用到inet_addr();
                       如address.sin_addr.s_addr=inet_addr("127.0.0.1").
                       用了inet_addr产生的是网络字节序,所以不需要再次使用。
                  (3)IP地址如果是INADDR_ANY,表示对本机的所有ip的某个端口进行监听。(一台主机往往有多个ip)
                       如address.sin_addr.s_addr=htonl(INADDR_ANY);
               bind成功返回0,失败返回-1.
       
   
      3. 创建套接字队列:
 
               int listen(int socket, int backlog);
              
               头文件:#include<sys/socket.h>
             
               功能:创建一个套接字队列,用来接收请求。
                     backlog是队列的长度,表示最多容纳多少个请求。

       4. 接收请求:
               
               int accept(int socket, struct sockaddr *address, size_t * address_len)
             
               头文件: #include<sys/socket.h>
 
               accept是阻塞形式的,可以通过改变套接字属性来改变这一属性。它会在listen队列中,取第一个请求后返回。
               address:是客户端的address。如果不关心客户的地址,可以设置为空指针。
               如果成功会返回新的套接字连接符。
               有了新的套接字连接符之后,可以像操作文件一样操作套接字。套接字是双工的。read和write都可以。

       5. 请求连接:
 
                int connect(int socket, const struct sockaddr *address, size_t address_len);

                头文件:#include<sys/socket.h>
               
                socket是本地的socket,地址是外地地址。
                connect成功会返回0,失败则返回-1。
                connect会被阻塞一定的时间。

       6. 关闭套接字:
                close(int socketfd);

       7. 改变套接字属性:

                int setsockopt(int socket,int level, int option_name, const void * option_value, size_t option_len);

                如果想在Socket层上改变属性,必须设置level为SOL_SOCKET。


 
 B  网络信息:
      1. 获取主机名:    
            int gethostname(char *name ,int namelength);
            获取本机名称放入name中,成功返回0,失败返回-1。
           
      2. 获取某台主机的IP地址:
             
               struct hostent * gethostbyname(const char *name);
                              
               #include <netdb.h>
                            
               查DNS或者本机的DNS表。
              
               hostent结构体:
                 struct hostent
                   {
                       char *h_name;             /* name of the host*/
                       char **h_aliases;        /*list of aliases*/
                       int  h_addrtype;         /*address type*/
                       int  h_length;           /*length in bytes of the address*/
                       char **h_addr_list;      /*list of address (network order)*/
                   }
              
        3. 打印套接字地址:
                 char * inet_ntoa(struct in_addr in);
                 将结构体套接字用点分十进制的方式打印出来。
      
   
C  select 系统调用:  
        1.fd_set 套接字文件集。
              void FD_ZERO(fd_set * fdset);             //将集合置空
              void FD_CLR(int fd, fd_set *fdset);       //将某个文件从集合中删除
              viod FD_SET(int fd, fd_set *fdset);       //将某个文件加入到集合中
              int  FD_ISSET(int fd, fd_set *fdset);     //测试某个文件是否在集合中,如果是返回非0值。
              fd_set中能够容纳的元素的个数由FD_SETSIZE值来限定。

         2.timeval, 防止select无限阻塞。
               struct timeval
                     {
                         time_t tv_sec;
                         long   tv_usec;
                      }

         3.select定义:

               int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout);

               readfds处于读操作就绪状态,writefds集合里有描述符处于写操作就绪状态,errorfds集合里有描述符遇到一个错误条件。

 
    poll系统调用:

        1.功能: 与select相似。从一组事件中响应一个事件。

        2.pollfd:用于存放需要检测其状态的Socket描述符;每当调用这个函数之后,
                 系统不会清空这个数组,操作起来比较方便;特别是对于socket连接比较多的情况下,
                 在一定程度上可以提高处理的效率;这一点与select()函数不同,调用select()函数之后,
                 select()函数会清空它所检测的socket描述符集合,导致每次调用select()之前都必须把
                 socket描述符重新加入到待检测的集合中;
            typedef struct pollfd
                 {
                       int     fd;          //文件号
                       short   events;      //对文件描述符上感兴趣的事件
                       short   revents;     //文件描述符实际发生的事件
                  }pollfd_t  
             常用事件是:POLLIN、POLLOUT、POLLERR   
             如:设置感兴趣的事件:fds[nIndex].events=POLLIN | POLLOUT | POLLERR;
                 检测是哪个事件发生了:f((fds[nIndex].revents & POLLIN) == POLLIN){...};
        
          3.int poll(struct pollfd fds[], nfds_t nfds, int timeout);
            #include<poll.h>
           
            fds[]  :文件描述符的集合
            nfds   :文件描述符个数
            timeout:超时,如果设置为0会立即返回,如果设置为INFIM,则一直阻塞。
           
            返回
              >0 : 发生事件的文件总数
              =0 :超时
              <0 : 错误发生

你可能感兴趣的:([Linux程序设计笔记]14章:套接字Socket)