linux/unix编程手册-56_60


title: linux/unix编程手册-55_56 date: 2018-10-05 11:53:07 categories: programming tags: tips

linux/unix编程手册-56(SOCKET 介绍)

socket是一种IPC方法。容许单台或经过网络链接的主句进程间交换数据linux

  • 各应用程序建立一个socket
  • 服务器将本身的socket绑定到一个都知道的地址上

fd=socket(domain, type, protocol)编程

系统调用

#include<sys/socket.h>

int socket(int domain, int type, int protocal) //return fd success, -1 error int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
//return 0 s, -1 e

struct sockaddr{
    sa_family_t sa_family;
    char        sa_data[14];
};
复制代码

socket缓存

  • domain:识别出socket的地址格式,代表通讯范围
  • type:SOCKET_STREAM(TCP)和SOCKET_DGRAM(UDP)
  • protocol 通常为0

对于fd,getsockname,getpeername服务器

流socket

#include<sys/socket.h>
int listen(int sockfd, int backlog);
//return 0 s, -1 e

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
//return fd success, -1 error

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
//return 0 s, -1 e
复制代码

主动和被动socket网络

  • 一个主动socket经过connect 创建一个到被动socket的链接
  • 一个被动socket经过listen 被标记成容许接入链接的socket

listen并发

  • backlog: 若是在服务器调用accept前,客户端connect,会产生一个未决的链接,backlog限制这个数量,在这个数量内,客户端链接请求会当即成功,数量外的会阻塞到一个未决链接被accept,并从未决链接队列删除

accept负载均衡

  • 会建立一个新的socket,这个新的socket会与connect另外一端的socket链接
  • addr和addrlen在调用事后会为对端地址信息,若是不关心对端信息传入时设为NULL,0

数据报socket

#nclude<sys/socket.h>

ssize_t recvfrom(int sockfd, void *buffer, size_t length, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
//return num of bytes received, 0 EOF, -1 error

ssize_t recvfrom(int sockfd, void *buffer, size_t length, int flags, struct sockaddr *dest_addr, socklen_t *addrlen);
//return num of bytes send, -1 error
复制代码
  • 客户端若是须要接受服务端发送的数据报的话还须要bind一下
  • 数据报能够connect以后调用write和直接send_to同样,只适用于发起connect的一端,connect以后内核会记录socket的对端,屡次调用connect后面的会修改前面的

linux/unix编程手册-57(SOCKET UNIX DOMAIN)

struct sockaddr{
    sa_family_t sa_family;
    char        sa_data[108];
};


const char *SOCKNAME = "/tmp/mysock";
int sfd;
struct sockaddr_un addr;
sfd = socket(AF_UNIX, SOCK_STREAM, 0); 
if (sfd == -1)
    errExit("socket");
/* Create socket */
memset(&addr, 0, sizeof(struct sockaddr_un));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, SOCKNAME, sizeof(addr.sun_path) - 1);
if (bind(sfd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un)) == -1)
    errExit("bind");
复制代码
  • 没法将socket绑定到一个已有路径名上,bind会返回EADDRINUSE
  • 没法open 打来一个socket
  • 当不须要一个socket时使用unlink
  • 若是sun_path的第一个字符为NULL字节,会建立抽象socket命名空间
    • 无需担忧名字和文件系统冲突
    • socket关闭后自动删除抽象名
    • 权限无需写权限

其余

#include<sys/socket.h>

int socketpair(int domain, int type, int protocol, int sockfd[2]);
复制代码
  • domian只能是AF_UNIX
  • 调用完sockpair以后,进程会fork一个子进程,子进程继承fd副本进行通讯

linux/unix编程手册-58(SOCKET TCP/IP网络基础)略

netstat -idom

linux/unix编程手册-59(SOCKET Internet Domain)

网络字节序

  • 因为端口号和IP地址须要被网络中的全部主机理解,须要统一标准字节序,即网络字节序,它是大端的
#include<arpa/inet.h>

// return netword byte order
uint16_t htons(uint16_t host_uint16);

uint32_t htonl(uint32_t host_uint32);

// return host byte order

uint16_t ntohs(uint16_t net_uint16);

uint32_t ntohl(uint32_t net_uint32);
复制代码

internet socket 地址

#include<netinet/in.h>

struct in_addr {                /* IPv4 4-byte address */
    in_addr_t s_addr;           /* Unsigned 32-bit integer */
};
struct sockaddr_in {            /* IPv4 socket address */
    sa_family_t sin_family;     /* Address family (AF_INET) */
    in_port_t sin_port;         /* Port number */
    struct in_addr sin_addr;    /* IPv4 address */
    unsigned char __pad[X];     /* Pad to size of 'sockaddr' structure (16 bytes) */
};

struct in6_addr {               /* IPv6 address structure */
    uint8_t s6_addr[16];        /* 16 bytes == 128 bits */
};
struct sockaddr_in6 {           /* IPv6 socket address */
    sa_family_t sin6_family;    /* Address family (AF_INET6) */
    in_port_t sin6_port;        /* Port number */
    uint32_t sin6_flowinfo;     /* IPv6 flow information */
    struct in6_addr sin6_addr;  /* IPv6 address */
    uint32_t sin6_scope_id;     /* Scope ID (new in kernel 2.4) */
};
复制代码
#include<arpa/inet.h>
// 二进制ip地址和可读ip地址('127.0.0.1')转换
int inet_pton(int domain, const char *src_str, void *addrptr);
//return 1 success, 0 格式str不催, -1 error
const char *inet_ntop(int domain, const void *addrptr, char *dst_str, size_t len);
//return dst_str的指针success, NULL error
复制代码

域名系统(DNS)

  • 解析也是从顶级域名开始一级级解析
  • 域名的补全规则定义在/etc/resolv.conf文件中,默认会用本机域名补全
  • /etc/services记录了(IANA)端口号和服务名

主机和服务的转换

#include<sys/socket.h>
#include<netdb.h>

int getaddrinfo(const char *host, const char *service, const struct addrinfo *hints, struct addrinfo **result);
//return 0 success, other error,可能须要向DNS服务器发请求

struct addrinfo {
    int ai_flags;               /* Input flags (AI_* constants) */
    int ai_family;              /* Address family (AF_INET | AF_INET6)*/
    int ai_socktype;            /* Type: SOCK_STREAM, SOCK_DGRAM */
    int ai_protocol;            /* Socket protocol */
    size_t ai_addrlen;          /* Size of structure pointed to by ai_addr */
    char *ai_canonname;         /* Canonical name of host */
    struct sockaddr *ai_addr;   /* Pointer to socket address structure */
    struct addrinfo *ai_next;   /* Next structure in linked list */
};

int freeaddrinfo(struct addrinfo *result);
//释放result分配的内存

int getnameinfo(const struct sockaddr *addr, socklen_t addrlen, char *host, size_t hostlen, char *service, size_t servlen, int flags);
// 0 success, other fail,不想要获取的参数传NULL,len设为0

复制代码

getaddrinfosocket

  • host 为主机名或者ip字符串
  • service 为一个服务名或者十进制端口号
  • hint指向的结构规定了,result返回的socket地址结构的标准。hint能够设置ai_flagsai_familyai_socktypeai_protocol字段用做过滤
  • result指向一个包含addrinfo结构链表的表头

CS实现代码(略)

linux/unix编程手册-60(SOCKET 服务器的设计)(大部分略)

并发型服务器的其余设计方案

  • 预先建立进/线程池,动态改变池大小
  • 单个进程处理多个客户端(I/O多路复用,信号驱动,或者epoll)
  • 服务器集群
    • DNS轮转负载共享,缓存,没法良好的负载均衡,没法确保高可用等一些问题
    • 负载均衡

inetd守护进程(看不到在用的)

用来消除运行大量很是用服务器进程的须要tcp

  • 监视一组指定套接字端口,按须要启动其它服务
  • 简化了启动其它服务的编程工做

inetd守护进程一般在系统启动时运行。以后执行以下步骤

  • /etc/inetd.conf中指定的每项服务,inetd都会建立一个恰当类型的套接字,而后绑定到指定端口上,TCP的话会listen
  • 经过select监视
  • select阻塞直到有请求,在TCP中会先accept建立新的socket
  • inetd调用fork建立一个新的进程,exec()启动服务器程序,在exec()以前
    • 除了socket描述符外,关闭其余继承的文件描述符
    • 在0,1,2上复制套接字文件描述符,关闭套接字文件描述符自己(这样相应代码直接从标准输出输入读取写入客户端信息就行了)
    • 为启动进程设定与用户和组ID
  • 若是是tcp而且accept建立了socket fd,inetd关闭这个描述符
  • 继续select监视
相关文章
相关标签/搜索