unix网络编程-第3,4章套接字编程

第3章 套接字编程简介

1.套接字的基本结构

数据定义:

struct sockaddr {

unsigned short sa_family; /* address族, AF_xxx */

char sa_data[14]; /* 14 bytes的协议地址 */

};

sa_family 一般来说,都是“AFINET”。

sa_data 包含了一些远程电脑的地址、端口和套接字的数目,它里面的数据是杂溶在一

切的。

为了处理struct sockaddr, 程序员建立了另外一个相似的结构 struct sockaddr_in:

struct sockaddr_in (“in” 代表 “Internet”)

struct sockaddr_in {

short int sin_family; /* Internet地址族 */

unsigned short int sin_port; /* 端口号 */

struct in_addr sin_addr; /* Internet地址 */

unsigned char sin_zero[8]; /* 添0(和struct sockaddr一样大小)*/

};

这个结构提供了方便的手段来访问socket address(struct sockaddr)结构中的每一个元

2.套接字字节转换程序的列表:

计算机内存中有两种数据存储方式,一种为小端字节序,也就是低地址存储数据低字节,高地址存储数据高字节;一种为大端字节序,也就是低地址存储高字节,高地址存储低字节。网络字节序采用大端字节序,而主机字节序有可能为小端字节序,因此,存在着字节序的转换问题。

l htons()——“Host to Network Short”主机字节顺序转换为网络字节顺序(对无符号

短型进行操作4 bytes)

l htonl()——“Host to Network Long” 主机字节顺序转换为网络字节顺序(对无符

号长型进行操作8 bytes)

l ntohs()——“Network to Host Short “ 网络字节顺序转换为主机字节顺序(对无符

号短型进行操作4 bytes)

l ntohl()——“Network to Host Long “ 网络字节顺序转换为主机字节顺序(对无符

号长型进行操作8 bytes)

3. IP 地址转换

in_addr_t inet_addr(const char *straddr);

  int inet_aton(const char* straddr,struct in_addr *addrp);

  char* inet_ntoa(struct in_addr inaddr);

头文件:sys/socket.h netinet/in.h arpa/inet.h

inet_addr成功返回32位网络字节序地址,出错返回INADDR_NONE。INADDR_NONE为linux定义的一个常数,是一个不存在的ip地址;

inet_aton将ASCII转换成网络字节序的32位二进制值,输入的ASCII放在straddr中,转换后放在addrp中,成功返回1,失败返回0;

inet_ntoa将32位二进制地址转换成ASCII地址,成功返回ASCII值,失败返回NULL。

Linux 系统提供和很多用于转换IP 地址的函数.首先,假设你有一个struct sockaddr_in ina,并且你的IP 是166.111.69.52 ,你想把你的IP 存储到ina 中。你可以使用的函数: inet_addr() ,它能够把一个用数字和点表

示IP 地址的字符串转换成一个无符号长整型。你可以像下面这样使用它:

ina.sin_addr.s_addr = inet_addr(“166.111.69.52”);

注意:

l inet_addr() 返回的地址已经是网络字节顺序了,你没有必要再去调用htonl() 函数

反过来,如果你有一个struct in_addr 并且你想把它代表的IP 地址打印出来(按照数字.数字.数字.数字的格式),那么你可以使用函数inet_ntoa()(“ntoa”代表“Network to ASCII”),它会把struct in_addr 里面存储的网络地址以数字.数字.数字.数字的格式。

l inet_ntoa() 使用struct in_addr 作为一个参数,不是一个长整型值。

4.字节操作函数   

字节操作函数主要是用于读取结构体中的某几个字节。

    void bzero(void *dest,size_t nbytes);

    void bcopy(const void *src,void *dest,size_t nbytes);

    int bcmp(const void *prt1,const void *ptr2,size_t nbytes);

    void *memset(void *dest,int c,size_t len);

    void *memcpy(void *dest,const void *src,size_t nbytes);

    int memcmp(const void *ptr1,const void ptr2,size_t nbytes);

头文件:string.h

说明:以b打头的函数为支持套接口函数的系统所提供,mem为支持ANSI C库提供的函数;其中,bzero将制定的起始地址设置为0(nbytes表示字长),bcopy和memcpy为复制,bcmp和memcmp为比较,memset将目标中指定数据的字节设置为指定的值。


5.readn,writen和readline函数


第4章 基于TCP套接字编程

基本TCP客户-服务器程序的套接口函数如下图:

1、socket函数

原型:#include<sys/socket.h>

int socket(int family, int type, int protocol); 返回值:非负描述符--成功, -1--出错;

作用:指定期望的通信协议接口(TCP或UDP或unix域字节协议等)

family 指明协议簇

解释
AF_INET IPv4协议
AF_INET6 IPv6协议
AF_LOCAL Unix与协议
AF_ROUTE 路由套接口
AF_KEY 密钥套接口
type类型

类型 解释
SOCK_STREAM 字节流套接口
SOCK_DGRAM 数据包套接口
SOCK_RAW 原始套接口

protocol参数应设置为某个协议类型常值,或者设为0.

protocol 说明
IPPROTO_TCP TCP传输协议
IPPROTO_UDP UDP传输协议
IPPROTO_SCTP SCTP传输协议

2、connect函数

原型:#include<sys/socket.h>

int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen);返回值:0---成功,-1----出错;

作用:客户端用connect 函数建立一个与TCP服务器的连接;

参数:sockfd,套接口描述字;

             servaddr,套接口地址结构的指针,该地址结构需要包含服务器IP地址和端口号;

             addrlen, 套接口地址结构的大小;

关于connect出错返回的几种情况:

  •  如果TCP客户端没有收到SYN分节的响应,则返回ETIMEDOUT。
  • 如果对客户的SYN的响应是RST,则表明该服务器主机在我们指定的端口上没有进程在等待与之连接,这称之为硬错,客户端接到RST,立即返回错误ECONNREFUSED;
  • 如果某客户端发出的SYN在中间的路由器上引发了一个目的地不可达的ICMP错误,这称之为软错,客户端按时间间隔继续发送SYN,在规定时间仍未收到响应,则返回EHOSTUNREACH;
3、bind函数

原型:#include<sys/socket.h>

int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);返回值:0---成功,-1----出错;

作用:给套接口分配一个本地协议地址;

参数:sockfd,套接口描述字;
    myaddr,特定于协议的地址结构的指针,对于TCP,可以指定一个IP地址,一个端口号;
           addrlen,第二个参数地址结构的长度;


4、listen函数

原型:#include<sys/socket.h>

int listen(int sockfd, int backlog);  返回值:0---成功,-1---出错;

作用 : 将未连接的套接口转换成被动套接口,指示内核应接受此套接口的连接请求;第二个参数规定了次套接口排队的最大连接数;

参数:sockfd,套接口描述字;

           backlog,套接口排队的最大连接数;

对与第二个参数backlog的理解:

  • 未完成连接队列,为每个已由客户端发出并到达服务器,服务器正在等待完成相应TCP三路握手过程的SYN分节开设一个条目,这些套接口都处于SYN_RCVD;
  • 已完成队列:为每个已完成TCP三路握手过程的客户开设一个条目,这些套接口都处于ESTABLISHED状态;
关系如下图:

5、accept函数
原型:#include<sys/socket.h>
int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);返回值:非负描述符---成功,-1----出错;
作用:有服务器调用,从已完成连接队列头返回下一个已完成连接,若已完成连接队列为空,则进程睡眠。
参数:sockfd,套接口描述字;
    cliaddr,客户进程协议地址;
   addrlen,第二个参数,客户进程协议地址的长度;

6、close函数
原型:#include<unistd.h>
int close(int sockfd);
作用:将套接口坐上“已关闭”标记,并立即返回到进程;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章