网络编程基础接口笔记

《unix网络编程》第四章笔记



1、网络编程首先就是调用socket函数,创建一个socket套接字描述符,类似于文件描述符

#include <sys/socket.h>
int socket(int family, int type, int protocol);

family 指定协议域,如:

family说明
AF_UNIX、AF_LOCALunix域协议
AF_INETIPV4 协议
AF_INET6IPV6 协议
AF_PACKET底层数据包接口

有时会看到使用PF_前缀的值,如PF_INET,PF_UNIX。AF_前缀表示地址族,PF_前缀表示协议族,man手册里有如下说明:
“The  manifest  constants  used  under 4.x BSD for protocol families are PF_UNIX, PF_INET, etc.,while AF_UNIX etc. are used for address families.  However, already the BSD man page  promises:"The protocol family generally is the same as the address family", and subsequent standards use AF_* everywhere.”

type 指明套接字类型,如

type说明
SOCK_STREAM字节流套接字
SOCK_DGRAM数据报套接字
SOCK_RAW原始套接字

protocol指定某个协议类型常值,或设为0,由所给定的family和type组合的系统默认值。

protocol说明
IPPROTO_CPTCP传输协议
IPPROTO_UDPUDP传输协议
IPPROTO_SCTPSCTP传输协议


2、客户通过connect函数与服务器建立连接

#include <sys/tocket.h>
int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen);

sockfd是由socket函数返回的套接字描述符。servaddr含有服务器的IP地址和端口号。
客户在调用connect前不必非调用bind函数,因为内核会确定源IP地址,并选择一个临时端口作为源端口。

该函数返回错误可能有以下几种情况:
(1)没有收到SYN分节的相应,返回ETIMEDOUT错误
(2)对客户的SYN相应RST,返回ECONNREFUSED错误
 RST是TCP在发生错误时发送的一种TCP分节,产生RST的三个条件是:目的地为某端口的SYN到达,然后该端口上没有正在监听的服务程序;TCP想取消一个已有连接;TCP接收到一个根本不存在的连接上的分节。(TCPV1第246~250有更详细的信息)
(3)客户发出的SYN在中间的某个路由器上引发“destination unreachable”(目的地不可达)ICMP错误,返回EHOSTUNREACH或ENETUNREACH错误。可能是在规定时间内没收到响应,或者根本没有到达远程系统,或者connect调用根本不等待就返回。

connect失败后,都必须close当前的套接字描述符并重新调用socket。


3、bind函数把一个本地协议地址赋予一个套接字。

#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);

socket是所要绑定的函数套接字;myaddr是一个指向特定于协议的地址结构的指针;addrlen是该地址结构的长度。

对于TCP,调用bind函数可以指定一个端口,或指定一个IP地址,或两者都指定,或都不指定,由内核选择。
一般服务器会绑定众所周知的端口号,而客户端则多为内核选择一个临时端口。
客户端通常也不绑定IP地址,当连接套接字时,由内核根据外出网络接口来选择源IP地址,而所用外出接口则取决与达到服务器所需的路径。TCP服务器如果没有绑定IP地址,内核则把客户发送的SYN的目的IP地址作为服务器的源IP地址。

对于IPV4,如要让内核选择IP地址,需将套接字地址设为通配地址INADDR_ANY,其值一般为0

struct sockaddr_in servaddr;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

对于IPV6

#include <netinet/in.h>
struct sockaddr_in6 serv;
serv.sin6_addr = in6addr_any;

如果让内核来选择临时端口号,必须注意,bind并不返回其值,因第二个参数有const限定词。为了得到内核所选选择的临时端口号,需调用函数getsockname来返回协议地址。
我们必须仔细区别一个分组的到达接口和该分组的目的IP地址 (8.8节)
bind返回的常见错误是EADDRINUSE (详见7.5节)


=======================

如需要绑定指定地址,则需要用到地址转换函数,用于字符串格式的地址形式和网络字节序的二进制值之间转换,如常见的下面几个函数:
#include <arpa/inet.h>
int inet_aton(const char *strptr, struct in_addr *addrptr);
in_addr_t inet_addr(const char *strptr); // 废弃,失败返回值与编译器有关
char *inet_ntoa(struct in_addr inaddr); // 返回的字符串保存在静态内存中,不可重入
上述转换函数除已写明的存在问题,还只适用于IPV4地址,更好的办法是使用两个全新的函数inet_pton和inet_ntop。p和n分别代表表达(presentation)和数值(numeric)。
#include <arpa/inet.h>
int inet_pton(int family, const char *strptr void *addrptr);
const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);
family可以是AF_INET,也可以是AF_INET6。
len参数是目标存储单元的大小,以免该函数溢出其调用者的缓冲区,为有助于指定这个大小,在<netinet/in.h>头文件中有如下定义:

#define INET_ADDRSTRLEN 16// for IPV4 dotted-decimal
#define INET6_ADDRSTRLEN 64 // for IPV6 hex string



4、服务端创建socket套接字后,并绑定本地地址后,调用listen函数,指示内核应接受该套接字的连接请求。

#include <sys/socket.h>
int listen(int sockfd, int backlog);
第二个参数backlog指定某个给定套接字上内核为之排队的最大已完成连接数。
这里需要了解下,内核为任何一个给定监听的套接字维护两个队列,如下图所示:




5、accept函数由TCP服务器调用,用于从已完成连接队列头返回下一个已完成连接。如已完成连接队列为空,则进程投入睡眠(假定套接字为默认的阻塞方式)

#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);
参数sockfd是前面listen监听的套接字描述符,如accept成功,则函数返回值则是内核生成的一个全新描述符,代表与所返回客户的TCP连接。

参数cliaddr和addrlen可用来获取客户端的协议地址,如没有必要,则可都置为NULL。


6、最后用close函数来关闭调节自,并终止TCP连接

#include <unistd.h>
int close(int sockfd);

这里有一个重要的概念,即每个文件或套接字都有一个引用计数。如下代码:

pid_t pid;
int listenfd, connfdl
listenfd = socket(...);
bind(listenfd, ...);
listen(listenfd, LISTENQ);


for ( ; ;)
{
	connfd = accept(listenfd, ...);
	if (pid = fork() == 0)
	{
		close(listenfd);
		doit(connfd);
		close(connfd);
		exit(0);
	}
	close(connfd);
}

在fork之前,listenfd和connfd描述符的引用计数值都为1;在fork之后,这两个描述符在子进程中被复制,引用计数都变为2。只有引用计数值变为0时,相应套接字才会真正的清理和资源释放。
如果不想等引用技术变为0才断开连接,可直接使用shutdown函数。


推荐阅读链接:

http://www.cnblogs.com/skynet/archive/2010/12/12/1903949.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值