第15章 套接字

 

创建套接字:

 

#include <sys/types.h>

#include <sys/socket.h>

int socket( int domain, int types, int protocol);

domain:

  AF_UNIX, AF_LOCAL      // address family  地址是文件名

  AF_INET   //IPV4

  AF_INET6  //IPV6

types:

  1. stream:  SOCK_STREAM    //流

  2. datagram: SOCK_DGRAM  //数据报

socket返回的描述符,用read和write调用

close系统调用结束socket连接

不同的domain 有不同的地址格式:

  AF_UNIX : 定义在sys/un.h 中

    struck sockaddr_un {

      sa_family_t  sun_family;

      char     sun_path[ ];

    };

  AF_INET : 定义在netinet/in.h中

  struct sockaddr_in {

    short int     sin_family;

    unsigned short int  sin_port;

    struct in_addr    sin_addr;

  };      其中:

      sruct in_addr {

        unsigned long int  s_addr;

      };

 

命名:   要使用创建好的套接字,需要命名.  //服务器端

#include <sys/socket.h>

int bind( int socket, const struct sockaddr *address, size_t address_len);  //succes return 0.

  作用是把socket定义的name space 指向 address所在的地址. 如:

 server_address.sun_family = AF_UNIX;
    strcpy(server_address.sun_path, "filename");
    server_len = sizeof(server_address);
     bind(server_sockfd, (struct sockaddr *)&server_address, server    _len);

 

 

建立套接字队列:  保存未处理的请求

 

  #include <sys/socket.h>

  int listen( int socket, int backlog);   //backlog位保存的最大个数    成功 返0

 

接收连接:

  服务器程序建立并命名了套接字后 可通过accept系统调用来等待客户建立对该套接字的连接

  #include <sys/socket.h>

  int accept( int socket, strucct sockaddr *sddress, size_t *address_len);

 

 

 

 

客户端请求连接:

#inclued <sys/socket.h>

int connect ( int socket, const struct socket sockaddr *address, size_t address_len);

关闭套接字:

  调用close来终止服务器和客户上的套接字连接.

    服务器: 一般在read调用返回0是关闭.

 

网络套接字:

  系统使用1024以内的端口. 端口可在文件: /etc/services 中查到.

  /etc/hosts 本地主机地址 及 共享网络地址

 

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

  inet_addr函数把网络地址转换位binary 地址

 

例:

int server_sockfd, client_sockfd;
int server_len, client_len;
struct sockaddr_in server_address;
struct sockaddr_in client_address;

server_sockfd = socket(AF_INET,SOCK_STREAM,0);

server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = inet_addr("127.0.0.1"); 

server_address.sin_port = 9734;
server_len = sizeof(server_address);
 bind(server_sockfd,(struct sockaddr *)&server_address,server_l    en);
 listen(server_sockfd, 5);

 接收来自计算机网络的任何网络接口连接: INADDR_ANY 32位整数 用在 sin_addr.s_addr 中,

不同的cpu存储的字节顺序不同,intel 是 4-3-2-1 高到低 ibm的是 低到高的顺序,这样导致ip地址不一样,解决方法是通过在netinet/in.h中函数完成:

#include <netinet/in.h>htonl  //host to net long 缩写

htons,ntohl,ntohs 函数   //我的centos 是 include <arpa/inet.h>中

服务器:

  server_address.sin_addr.s_addr = htonl(INADDR_ANY);

  server_address.sin_port = htons(9734);

客户端:

  address.sin_addr.s_addr = inet_addr("127.0.0.1"); //不变

  address.sin_port = htons(9374);

 

 

网络信息:   主机数据库函数

  #include <netdb.h>

  struct hostent *gethostbyaddr(const void *addr, size_t len, int type);

  struct hostent *gethostbyname(const char *name);

其中:

  struct hostent {

    char *h_name;

    char **h_aliases;

    int h_addrtype;

    int h_length;

    char **h_addr_list

  };

 

 服务信息函数:

  #include <netdb.h>

  struct servent *getservbyname(const char *name,const char *proto);

  struct servent * getservbyport( int port,const char *proto);

如: servinfo = getservbyname(“daytime”, “tcp”);

  printf(“daytime port is %d\n”, ntohs(servinfo -> s_port));

其中:

  proto包含tcp和udp两个参数--->SOCK_STREAM,  SOCK_DGRAM

  struct servent {

    char *s_name;

    char **s_aliases;

    int s_port;

    char *s_proto;

  };

 要获得某计算机主机数据库信息,可用gethostbyname,但要注意返回地址列表转换位正确的

地址类型,并用函数inet_ntoa将其从网络字节序转换位可打印的字符串.

  #include <arpa/inet.h>

  char *inet_ntoa(struct in_addr in)  // inet_addr(*(struct in_addr *)*a->h_addr_list);

  其作用是将因特网主机地址转换为一个点分四元组格式的字符串.

另:

  #include <unistd.h>

  int gethostname(char *name, int namelength)   

  作用是将当前主机的名字写入name指向的字符串.

 

 

 

 

 

internet 守护进程(deamon) xinetd/inetd)

  /etc/xinetd.conf and files in
  /etc/xinetd.d directory

 

多客户:

  在server程序中,使用fork(),

 例:

  socket(), bind(),listen() 后, if(fork == 0) //子进程,  进行操作: read(fd,buffer,) write(fd,buffer, ) close(fd)

              else //父进程 : close(fd);

 

select系统调用:

  select函数多数据结构fd_set进行操作,,它是由打开的文件描述符构成的集合. 有一组定义好的宏可以用来控制这些集合:

#include <sys/types.h>

#incldue <sys/time.h>

void FD_ZERO(fd_set *fd);     // 初始化fd_set为空集合

void FD_CLR( int fd,fd_set *fdset);   //

void FD_SET(int fd, fd_set *fdset);

int FD_ISSET(int fd, fd_set *fdset); // 如果 fd 是 fdset所指向的结构中的元素,则返回非0值

fd_set中文件描述符最大数由常量FD_SETSIZE指定.

 

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

select调用测试文件描述符集合中,是否有一个文件描述符已处于可读状态或可写状态或错误

状态,它将阻塞以等待某个文件描述符进入上述这些状态.

返回值为准备好的文件描述符的个数,未发生变化的文件描述符在fd_set 中清零. 用FD_ISSET查找改动的fd.

ioctl(fd,FIONREAD,&int_val);读取缓存中的字节数并将其储存到整型变量int_val中

 

 

 使用selectd多客户:

 

 

数据报:datagrams

  当客户需要发送一个短小的查询请求给server,并希望接收一个短小的相应时,使用UDP提供的服务. UDP 在局域网中非常可靠.

方法:

  套接字和close系统调用. 但用sendto和recvfrom代替read和write调用.

开启daytime服务的方法:

  vi  /etc/xinet.d/daytime-udp   将disable的yes改为no,然后重启 systemctl restart xinetd.service

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

    

 

posted @ 2016-04-22 22:31  孤灯下的守护者  阅读(170)  评论(0编辑  收藏  举报