APUE读书笔记------16章 网络IPC:套接字

一、引言

网络IPC:网络进程间通信(network IPC)

通过套接字网络IPC接口和其他进程通信。同样的接口既可以用于计算机间通信也可用于计算机内通信。

本章讨论仅限于因特网事实上的通信标准:TCP/IP协议栈。

二、套接字描述符

套接字是不同主机之间的进行进行双向通信的断点,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程。

要访问套接字就要使用套接字描述符,就像访问文件就要使用文件描述符一样。

1、创建套接字

#include <sys/socket.h>

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

返回值:成功则返回文件(套接字)描述符,出错返回-1.

domain确定通信的特性,包括地址格式。

                AF_INET IPv4因特网域

AF_INET6 IPv6因特网域

AF_UNIX UNIX域

AF_UNSPEC 未指定

type确定套接字的类型,进一步确定通信特征。

SOCK_DGRAM 长度固定的、无连接的不可靠报文传递

SOCK_RAW IP协议的数据报接口(POSIX.1中为可选)

  SOCK_SEQPACKET 长度固定、有序、可靠的面向连接报文传递

SOCK_STREAM有序、可靠、双面的面向连接字节流

protocol通常是0,表示按给定的域和套接字类型选择默认协议。AF_INET,SOCK_STREAM的默认是TCP(传输控制协议)。AF_INET,SOCK_DGRAM的默认是UDP(用户数据包协议).

2、禁止套接字上的输入、输出

#include <sys/socket.h>

int shutdown(int sockfd,int how);

如果how是SHUT_RD,就无法从套接字上读取数据,如果how是SHUT_WR,就无法使用套接字发送数据。使用SHUT_RDWR无法读取和发送数据。

三、寻址

两个标识:计算机的网络地址可以帮助标识网络上想与之通信的计算机;服务可以帮助标识计算机上特定的进程。

字节序:大端字节序(大地址代表低字节),小端字节序(大地址代表高字节)。linux是小端字节序。

3、处理器字节序和网络字节序的转换

#include <arpa/inet.h>

uint32_t htonl(uint32_t hostint32);       //主机到网络长整数

uint16_t htons(uint16_t hostint16); //主机到网络短整数

uint32_t ntohl(uint32_t netint32); //网络到主机长整数

uint16_t ntohs(uint16_t netint16); //网络到主机短整数

h表示主机(host)字节序;n表示网络(net)字节序;l表示长整数;s表示短整数。

地址格式:

通用地址结构:

struct sockaddr{

sa_family_tsa_family;/*addr family*/

char  sa_data[]; /*variable-length address*/

...

};

IPv4套接字地址:

struct in_addr{

in_addr_t s_addr; /*IPv4 addr:uint32_t*/

};

struct sockaddr_in{

sa_family_tsin_family;/*address family*/

in_port_t sin_port; /*port number:uint16_t*/

struct  in_addr sin_addr;/*IPv4 address*/

};

IPv6套接字地址:

struct in6_addr{

uint8_t s6_addr[16]; /*IPv6 addrt*/

};

struct sockaddr_in6{

sa_family_tsin6_family;/*address family*/

in_port_t sin6_port; /*port number:uint16_t*/

uint32_t sin6_flowinfo; /*traffic class and flow info*/

struct  in6_addr sin6_addr;/*IPv6 address*/

uint32_t sin6_scope_id; /*set of interfaces for scope*/

};

4计算机理解的地址格式和人理解的地址格式之间的转换

#include<arpa/inet.h>

const char *inet_ntop(int domain, const void *restrict addr, char *restrict str,socklen_t size);    /*将网络字节序的二进制地址转化成为文本格式字符串*/

返回值:成功返回地址字符串指针,出错返回NULL

size指定了用以保存文本字符串的缓冲区的大小,INET_ADDRSTRLEN用来存放IPv4地址的文本字符串;INET6_ADDRSTRLEN用来存放IPv6地址的文本字符串

int inet_pton(int domain, const char *restrict str, void *restrict addr);/*将文本格式字符串转化成为网络字节序的二进制地址*/

返回值:成功则返回1,若格式无效则返回0,出错返回-1.

缓冲区addr要足够发来存放32位IPv4地址,或者128位IPv6地址。

参数domain仅支持两个值:AF_INET和AF_INET6。


地址查询:

5、找到给定计算机的主机信息

#include<netdb.h>

struct hostent *gethostent(void); /*如果主机文件没有打开,该函数会打开,返回文件的下一个条目*/

返回值:成功返回指针,错误返回NULL

void sethostent(int stayopen); /*打开文件,如果文件已经被打开,那么将其绕回*/

void endhostent(void); /*关闭文件*/

struct hostent{

char *h_name;/*name of host*/

char **h_aliases;/*pointer to alternate host name array*/

int  h_addrtype; /*address type*/

int  h_length; /*length in bytes of address*/

char  **h_addr_list; /*pointer to array of network addresses*/

...

};

6、获得网络名字和网络号

#include<netdb.h>

struct netent *getnetbyaddr(uint32_t  net,int type);

struct netent *getnetbyame(const char *name);

struct netent *getnetent(void);

以上三个函数返回值:成功返回指针,出错返回NULL

void setnetent(int stayopen);

void endnetent(void);

netent结构体:

struct  netent{

char  *n_name; /*network name*/

  char  **n_aliases; /*alternate network name array pointer*/

int  n_addrtype; /*address type*/

uint32_t  n_net;/*network number*/

...

};

7、协议名称和协议号可以采用以下的映射

#include <netdb.h>

struct protoent *getprotobyname(const char *name);

struct protoent *getprotobynumber(int proto);

struct protoent *getprotoent(void);

以上函数的返回值:若成功返回指针,若出错返回NULL

void setprotoent(int stayopen);

void endprotoent(void);

struct protoent{

char *p_name;/*protocol name*/

char **p_aliases;/*pointer to alternate protocol name array*/

int p_proto;/*protocol number*/

...

};

8、

#include <netdb.h>

struct servent *getservbyname(cosnt char *name,const char *proto); /*将一个服务名字映射到一个端口号*/

struct servent *getservbyport(int port, const char *proto);/*将一个端口号映射到一个服务名*/

struct servent *getservent(void); /*顺序扫描服务数据库*/

以上三个函数的返回值:若成功返回指针,若出错返回NULL

struct setservent(int stayopen);

void endservent(void);

struct servent{

char  *s_name; /*servce name*/

char  **s_aliases; /*pointer to alternate service name array*/

int  s_port; /*port number*/

char  *s_proto; /*name of proto*/

...

};

9、

#include <sys/socket.h>

#include <netdb.h>

int getaddrinfo(const char *restrict host, /*将一个主机名字和服务名字映射到一个地址*/

    cosnt char *restrict service,

    const struct addrinfo *restrict hint,

    struct addrinfo**restrict res);

返回值:若成功返回0,若出错返回非0错误码

void freeaddrinfo(struct addrinfo *ai);

struct addrinfo{

int  ai_flags; /*customize behavior*/

int  ai_family; /*address family*/

int  ai_socktype; /*socket type*/

int  ai_protocol; /*protocol*/

socklen_t ai_addrlen; /*length in bytes of address*/

struct sockaddr*ai_addr;/*address*/

char *ai_canonname; /*canonical name of host*/

struct  addrinfo*ai_next;/*next in list*/

...

};

10、将地址转化为主机名或者服务名

#include <sys/socket.h>

#include <netdb.h>

int getnameinfo(const struct sockaddr  *restrict addr,

       socklen_t   alen,char *restrict host,

       socklen_t   hostlen,char *restrict service,

socklen_t  servlen,unsigned int flags);

返回值:若成功返回0,若出错返回非零的值。

四、将套接字与地址绑定

11、将地址绑定到一个套接字

#include <sys/socket.h>

int bind(int sockfd,const struct sockaddr *addr,socklen_t len);

返回值:若成功返回0,若失败返回-1

12、获得绑定到套接字的地址

#include <sys/socket.h>

int getsockname(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict alenp);

返回值:成功返回0,失败返回-1.

13、如果套接字已经和对方链接,调用getpeername来找到对方的地址

#include <sys/socket.h>

int getpeername(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict alenp);

返回值:若成功返回0,失败返回-1.

五、建立连接

14、建立连接

#include <sys/socket.h>

int connect (int sockfd, cosnt struct sockaddr restrict *addr,socklen_t len);

返回值:若成功返回-,失败返回-1.

addr为想与之通信的地址。

15、宣告可以接受连接请求

#include <sys/socket.h>

int listen (int sockfd, int backlog);

返回值:成功返回0,失败返回-1.

                backlog:该进程所要入队的连接请求数量,一旦队列满,系统会拒绝多余连接的请求。

16、获得连接请求并建立连接

#include  <sys/socket.h>

int accept(int sockfd, struct sockaddr *restrict addr,socklen_t *restrict len);

返回值:若成功返回文件(套接字)描述符,若失败返回-1.

六、数据传输

17、发送函数1

#include <sys/socket.h>

ssize_t send(int sockfd,const void *buf, size_t nbytes ,int flags);

返回值:成功返回发送到字节数,失败返回-1

18、发送函数2

#include <sys/socket.h>

ssize_t sendto(int sockfd, cosnt void *buf, size_t nbytes, int flags, cosnt sruct sockaddr *destaddr, socklen_t destlen);

返回值:成功返回发送的字节数,失败返回-1.

19、发送函数3

#include <sys/socket.h>

ssize_t sendmsg(int sockfd, const struct msghdr *msg,int flags);

返回值:若成功返回发送的字节数,若出错返回-1.

struct msghdr{

void  *msg_name; /*optional address*/

socklen_t msg_namelen; /*address size in bytes*/

struct  iovec*msg_iov;/*array of I/O buffers*/

int  msg_iovlen; /*number of elements in array*/

void  *msg_control; /*ancillary data*/

socketlen_tmsg_flags;/*flags for received message*/

...

};

20、接受数据1

#include <sys/socket.h>

ssize_t recv(int sockfd, void *buf, size_t nbytes, int flags);

返回值:以字节计数的消息长度,若无可用信息或对方已经按序结束则返回0,若出错则返回-1.

flags:套接字调用标志

MSG_OOB 如果协议支持,接收带外数据

MSG_PEEK 返回报文内容而不是真正取走报文

MSG_TRUNC 即使报文被截断,要求返回的是报文的实际长度

MSG_MAITALL 等待直到所有的数据可用

21、接受数据2

#include <sys/socket.h>

ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

返回值:以字节计数的消息长度,若无可用信息或对方已经按序结束则返回0,否则返回-1.




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值