1.24k likes | 1.47k Views
网络编程技术. 设计、制作、授课 : 谭献海 Email : xhtan@swjtu.edu.cn. 常用的网络编程技术(方法) : 数据链路级(帧) 直接网卡编程(可编程芯片) 基于 packet driver 的编程技术 基于 NDIS ( Network Driver Interface Specification ) 的网络编程 VPACKET , PACKET32 BPF ( Libpcap/winpcap) 网络层或传输层( IP/TCP/UDP ): Berkeley Sockets 编程技术 Winsock JAVA 网络编程 高级:
E N D
网络编程技术 设计、制作、授课:谭献海 Email:xhtan@swjtu.edu.cn
常用的网络编程技术(方法) : 数据链路级(帧) 直接网卡编程(可编程芯片) 基于packet driver的编程技术 基于NDIS( Network Driver Interface Specification )的网络编程 VPACKET,PACKET32 BPF(Libpcap/winpcap) 网络层或传输层(IP/TCP/UDP): Berkeley Sockets编程技术 Winsock JAVA网络编程 高级: JAVA网络编程 ASP,PHP,JSP,.net (自学) 高级语言网络编程类库(VB,VC,delphi)(自学) 网络编程技术(方法)概述
Topics Socket编程基础 Socket函数介绍 基于socket的通信流程 Socket编程实例 Socket编程技术
Internet Client Process Server Process Internet transport layer (TCP/UDP) transport layer (TCP/UDP) network layer (IP) network layer (IP) link layer (e.g. ethernet) link layer (e.g. ethernet) physical layer physical layer Internet Sockets as means for inter-process communication (IPC) application layer application layer Socket Socket OS network stack OS network stack • An interface between application and the network • The application can send/receive data to/from the network -- communication
What is a socket? To the kernel, a socket is an endpoint of communication. To an application, a socket is a file descriptor that lets the application read/write from/to the network. Remember: All Unix I/O devices, including networks, are modeled as files. (So as Windows) Clients and servers communicate with each by reading from and writing to socket descriptors. The main distinction between regular file I/O and socket I/O is how the application “opens” the socket descriptors. Sockets
Socket API UC Berkeley BSD unix /Berkeley unix De facto standard socket 通信协议应用程序接口(APIs)----依赖于操作系统和编程语言 UNIX: Berkeley Sockets (C语言) System V: Transport Layer Interface (TLI) (C语言) WINDOWS:WINSOCK
socket是实现进程间通信(IPC)的 BSD 方法。 类比:客户将插头插入一个服务器端口 建立一个双向的连接管道 socket的抽象表示 客户端 服务器 插口(port)
网络地址 (network address) IP地址 (IP Address) 2种不同的通信方式(面向连接/无连接) 流(Stream) 阻塞(Block)、非阻塞(Non-block) 同步(Synchronous)、异步(asynchronous) 字节顺序(Bytes Order) 带外数据(Out-of-band Data) 一些有关Socket编程的概念
Each host machine (or network interface) has an/more IP address A Socket-eye view of the Internet medellin.cs.columbia.edu (128.59.21.14) newworld.cs.umass.edu (128.119.245.93) cluster.cs.columbia.edu (128.59.21.14, 128.59.16.7, 128.59.16.5, 128.59.16.4)
Each host application has one/more ports (1~65,536) Some ports (0~1023) are reserved for specific applicatons 20,21: FTP 23: Telnet 80: HTTP … Ports Port 0 Port 1 Port 65535
An address is an IP + port A socket provides an interface to an IP:port pair Address Pair Local IP: 111.22.3.4 Local Port: 2249 Remote IP: 123.45.6.78 Remote Port: 3726
流式套接字(SOCK_STREAM) 提供了一种面向连接、可靠的数据传输服务,数据无差错、无重复的发送且按发送顺序接收。内设置流量控制,避免数据流淹没慢的接收方。数据被看作是字节流,无长度限制。 数据报套接字(SOCK_DGRAM) 提供无连接服务。数据包以独立数据包的形式被发送,不提供无差错保证,数据可能丢失或重复,顺序发送,可能乱序接收。 原始套接字(SOCK_RAW) 可以对较低层次协议,如IP、ICMP直接访问。 原始套接字保存了数据包中的完整IP头,而流和数据报两种套接字只能收到IP数据。 Socket类型
SOCK_STREAM a.k.a. TCP reliable delivery in-order guaranteed connection-oriented bidirectional SOCK_DGRAM a.k.a. UDP unreliable delivery no order guarantees no notion of “connection” can send or receive socket socket D1 3 2 1 Dest. 3 2 D2 1 App App D3 Two essential types of sockets
所谓流,是指一串具有相同的5元组(源IP地址、目的IP地址、协议和传输层源/目的端口号)的分组的集合。所谓流,是指一串具有相同的5元组(源IP地址、目的IP地址、协议和传输层源/目的端口号)的分组的集合。 流(Stream)
Problem: different machines / OS’s use different word orderings little-endian: lower bytes first, e.g. Intel CPU big-endian: higher bytes first, e.g. Motorola 68k CPU these machines may communicate with one another over the network 128 128 119 119 40 40 12 12 byte-ordering Big-Endian machine Little-Endian machine 12.40.119.128 128.119.40.12
All values stored in a sockaddr_inmust be in network byte order (NBO:big-endian). Whenever the source of the address isn’t the network, use htonl and htons to transform Network Byte Order Common Mistake: Ignoring Network Byte Order
流套接口的抽象中包括了带外数据这一概念 带外数据是相连的每一对流套接口间一个逻辑上独立的传输通道 带外数据是独立于普通数据传送给用户的,这一抽象要求带外数据设备必须支持每一时刻至少一个带外数据消息被可靠地传送 在任何时刻仅有一个带外数据信息等候发送 对于仅支持带内数据的通讯协议(例如IP)来说,紧急数据是与普通数据在同一序列中发送的,系统通常把紧急数据从普通数据中分离出来单独存放(看成是带外数据)。 带外数据
数据类型:#include <sys/types.h> 函数定义:#include <sys/socket.h> 地址类型: netdb.h Berkeley socket需要用到的头文件
网络连接函数 获取/设置socket的参数或信息函数 转换函数 Berkeley Socket 常用函数列表
Specify local and remote communication endpoints Initiate a connection Send and receive data Terminate a connection Network Functions needed:
socket bind connect listen accept select recv, recvfrom send, sendto close, shutdown Network Functions needed:
网络信息检索函数 gethostname 获取主机名 getpeername 获取与套接口相连的远程协议地址 getsockname 获取套接口本地协议地址 gethostbyname 根据主机名获取主机信息 gethostbyaddr 根据主机地址获取主机信息 getprotobyname 根据协议名获取主机协议信息 getprotobynumber 根据协议号获取主机协议信息 getservbyname 根据服务名获取相关服务信息 getservbyport 根据端口号获取相关服务信息 getsockopt/setsockopt 获取/设置套接口选项 ioctlsocket 设置套接口的工作方式 获取/设置socket的参数或信息
IP地址转换 inet_addr() inet_ntoa() 字节顺序转换 htons()--"Host to Network Short" htonl()--"Host to Network Long" ntohs()--"Network to Host Short" ntohl()--"Network to Host Long" Notes: Short—16bit; Long—32bit 转换函数
struct sockaddr { unsigned short sa_family; /* address family, AF_xxx */ char sa_data[14]; /* 14 bytes of protocol address */ }; 此数据结构用作bind、connect、recvfrom、sendto等函数的参数,指明地址信息 数据结构:sockaddr
The address family is one of AF_UNIX Unix internal protocols AF_INET Internet protocols AF_NS Xerox NS protocols AF_IMPLINK IMP link layer 其中,AF_ 代表“Address Family” socket address
Socket地址的数据部分根据不同的地址类型来解释,常见的地址类型是Internet、XNS和UNIX。Socket地址的数据部分根据不同的地址类型来解释,常见的地址类型是Internet、XNS和UNIX。 socket address
2-byteFamily 2-byteFamily 2-byteFamily 2-byte port 4-byte net ID Pathname (up to 108 bytes) 6-byte host ID 4-byte netid,hostid 2-byte port (unused) (unused) socket address structures for Internet,XNS and Unix families Struct sockaddr_in(因特网) Struct sockaddr_ns(XNS) struct sockaddr_un(Unix)
对于使用最多的Internet簇,其网络地址主要包括两大部分:端口号和IP地址,它的地址结构在<netinet/in.h>中定义对于使用最多的Internet簇,其网络地址主要包括两大部分:端口号和IP地址,它的地址结构在<netinet/in.h>中定义 因特网地址
Internet地址 struct sockaddr_in { short int sin_family; /* Address family */ unsigned short int sin_port; /* Port number */ /* 16-bit port number , network byte ordered */ struct in_addr sin_addr; /* Internet address */ /* 32-bit netid/hosted (IP)地址,network byte ordered */ unsigned char sin_zero[ 8]; /* unused */ }; 该结构与sockaddr兼容,供用户填入IP地址参数 数据结构:sockaddr_in
端口号通常分为三个范围块 0 ~ 1023:由IANA(Internet Assigned Numbers Authority)管理,保留为公共的服务使用 1024 ~ 49151:普通用户注册的端口号 49152 ~ 65535:动态或私有的端口号 sin_port
struct sockaddr_in my_addr; my_addr.sin_family = AF_INET; my_addr.sin_port = htons(3490); /* short, NBO*/ my_addr.sin_addr.s_addr = inet_addr("132.241.5.10"); bzero(&(my_addr.sin_zero), 8); 程序中填写sockaddr_in结构
特殊地址INADDR_ANY允许服务器监听主机的每个网络接口上的客户机活动,相当于地址0.0.0.0 。采用多个网卡的话,使用这种bind,将在所有网卡上进行绑定。在这种情况下,你可以收到发送到所有有效地址上数据包。 特殊地址INADDR_BROADCAST用于在一个IP网络中发送广播UDP数据报。要使用这个特殊地址,需要应用设置套接字选项SO_BROADCAST。 特殊地址
功能:创建一个socket 函数调用: int socket(int family, int type, int protocol); 函数返回Socket描述符,返回-1表示出错 family参数一般取AF_INET, protocol参数一般取0 应用示例: TCP:sockfd = socket(AF_INET,SOCK_STREAM,0); UDP:sockfd =socket(AF_INET, SOCK_DGRAM,0); socket()
‘int protocol’通常设定为0。这样的目的是使系统选择默认的由协议族和连接类型所确定的协议,如: sockfd = socket(AF_INET, SOCK_STREAM, 0); /* create TCP socket */ socket() Note: 0 implies IP_PROTO_TCP • 也有少量的特殊应用场合,需要特别声明具体的协议域。 • “协议”域与“family”域及“type”域的可能组合如下:
Family Type Protocol Antual protocol AF_INET AF_INET AF_INET AF_INET SOCK_DGRAM SOCK_STREAM SOCK_RAW SOCK_RAW IPPROTO_UDP IPPROTO_TCP IPPROTO_ICMP IPPROTO_RAW UDP TCP ICMP IP AF_NS AF_NS AF_NS AF_NS SOCK_STREAM SOCK_SEQPACKET SOCK_RAW SOCK_RAW NSPROTO_SPP NSPROTO_SPP NSPROTO_ERROR NSPROTO_RAW SPP SPP Error Protocol (raw) “协议” 与“family” 及“type”域的可能组合 常见TCP/IP协议的定义: #define IPPROTO_IP 0 #define IPPROTO_ICMP 1 #define IPPROTO_IGMP 2 #define IPPROTO_TCP 6 #define IPPROTO_UDP 17 #define IPPROTO_RAW 255
在服务器上运行,给socket指定一个众所周知的 (well-known) 端口地址 int bind (int sockfd, const struct sockaddr *myaddr, socklen_t addrlen) IP 地址+端口号 bind() 如果调用成功,则返回值为0,如果调用失败返回值为-1,并设定相应的错误代码errno。最常见的错误是该端口已经被其他程序绑定。 需要注意的一点:在Linux系统中,小于1024的端口(即众所周知的端口)只有拥有root权限的程序才能绑定
Bind()系统调用主要用于: A)服务员向系统注册它的众所周知的地址,它告诉系统:“这是我的地址(服务),所有以这个地址接收的报文都交给我,由我来服务。”面向连接和无连接的服务员在接受顾客的请求之前都必须做这一步。 B)顾客可为它自己注册一个特定的地址,以便通信的对方(服务员)可以用这个有效的地址送回响应,这就像在信封上写明回信地址的道理一样。 bind()
SOCK_DGRAM: if only sending, no need to bind. The OS finds a port each time the socket sends a packet if receiving, need to bind SOCK_STREAM: The OS binds a port to the client during connection setup Skipping the bind()
A connection occurs between two kinds of participants passive: waits for an active participant to request connection active: initiates connection request to passive side Once connection is established, passive and active participants are “similar” both can send & receive data either can terminate the connection Connection Setup (SOCK_STREAM)
Passive participant step 1: listen (for incoming requests) step 3: accept (a request) step 4: data transfer The accepted connection is on a new socket The old socket continues to listen Active participant step 2: request & establish connection step 4: data transfer l-sock a-sock-1 socket socket a-sock-2 Connection setup cont’d Passive Participant Active 1 Active 2
服务器开始监听已经绑定的端口 需要在此前调用bind()函数,否则由系统指定一个随机的端口 int listen(int sockfd, int queue_length); 接收队列 一个新的Client的连接请求先被放在接收队列中,等待Server程序调用accept函数接受该连接请求 queue_length用于指定接收队列的长度, 也就是在Server程序调用accept函数之前最大允许进入的连接请求数,多余的连接请求将被拒绝,典型取值为5 listen() 调用
1. socket() 2. bind(80) 3. listen() 80 Listen queue 服务器初始化 Web 服务器 操作系统
客户端建立与服务器的连接 int connect (int sockfd, const struct sockaddr *servaddr, socklen_t addrlen) servaddr是事先填写好的结构,用于指定所要连接的服务器的地址(Server的IP地址和端口号)。 connect() 调用
建立与服务器的连接 Web 服务器 1. socket() 客户 2. bind(80) 3. listen() connect() OS 80 Listen queue Request from (IP, port)
服务器忙 Web 服务器 客户请求在listen队列中获取先进先出服务(排队) 操作系统 80 Listen 队列 客户1 客户2 客户3
在阻塞模式下,当无法建立连接时connect的阻塞时间为20秒左右,可采用gethostbyaddr事先判断到服务主机的路径是否是通的,或者先ping一下对方主机的IP地址。 采用gethostbyaddr阻塞时间不管成功与否均为4秒左右。 采用Ping方式时间约2秒左右 connect