Download presentation
Presentation is loading. Please wait.
1
标准TCP/IP编程接口 ——Socket
2学时
2
网络应用编程接口 (API) 应用与协议软件间的接口 Application Network API Protocol A
Protocol B Protocol C
3
Network API的期望特征 通用编程接口. 支持面向报文和面向连接的通信. 与已有的I/O服务一致 操作系统无关 支持多种通信协议族
地址(端点)表示的独立性 支持面向报文和面向连接的通信. 与已有的I/O服务一致 操作系统无关
4
TCP/IP TCP/IP 并不包含API的定义. 使用TCP/IP有多种API: Sockets TLI, XTI Winsock
MacTCP
5
TCP/IP API的功能需求: 指定本地和远端的通信端点 发起连接 等待到来的连接 发送和接收数据 gracefully终止连接
错误处理(很重要)
6
什么是Socket Socket:套接口 P182:它是网络通信端点的一种抽象概念,为用户提供了一种发送和接收数据的机制。
Socket也是IO服务的一种,正如文件、管道等一样。 Sockets (obviously) have special needs: 建立一个连接 指定通信端点的地址 windows定义 typedef unsigned int u_int; typedef u_int SOCKET; P192
7
创建 Socket P191 SOCKET socket(int af, int type, int proto);
Af指协议族 (AF_INET for TCP/IP). type 指套接口类型 (SOCK_STREAM, SOCK_DGRAM,SOCK_RAW). protocol 指所用的协议 (通常为0,只有创建原始套接口,才需要设置). socket()函数(system call)正常情况返回一个套接口描述符,出错时返回INVALID_SOCKET socket()为一个通信端点分配了所需的资源——但是它并没有涉及编址 (addressing)的问题
8
指定端点的地址 记住sockets API是通用的. 必须有一种通用的方式来指定端点地址
TCP/IP中每个端口地址需要一个IP地址和一个端口号 其它的协议族可能使用其它的方案
9
通用socket地址 P185 struct sockaddr {
u_short sa_family; /* address family */ char sa_data[14]; /* up to 14 bytes of direct address */ }; sa_family 指定地址类型. sa_data指定地址的值
10
Sockaddr的通用性 它是一个能允许我使用套接口来与朋友通信的地址 地址类型:AF_FRIENDS 地址值: 张三 1 李四 2
11
AF_FRIENDS 初始化一个sockaddr结构来指向张三: zhangsan.sa_family = AF_FRIENDS;
struct sockaddr zhangsan; zhangsan.sa_family = AF_FRIENDS; zhangsan.sa_data[0] = 1;
12
AF_INET 对于 AF_FRIENDS,我们仅仅需要一个字节来指定地址 对于 AF_INET,我们需要: IPv4 only!
16 bit port number 32 bit IP address IPv4 only!
13
struct sockaddr_in (IPv4) P183
short sin_family; u_short sin_port; struct in_addr sin_addr; char sin_zero[8]; }; A special kind of sockaddr structure sin_zero:使该结构的大小与sockaddr相同
14
struct in_addr P183 32位的IPv4地址
15
IPv4 Address Conversion
Unsigned long inet_addr(); 字符串转化为in_addr地址结构适用的32位整数 char FAR*inet_ntoa(); 转化为字符串 顺便看一下gethostbyname() Hostent结构比较复杂,请参阅winsock2.h
16
Ignoring Network Byte Order
所有sockaddr_in结构中的值必须是网络字节序 sin_port a TCP/IP port number. sin_addr an IP address. Common Mistake: Ignoring Network Byte Order
17
Network Byte Order Functions
‘h’ : host byte order ‘n’ : network byte order ‘s’ : short (16bit) ‘l’ : long (32bit) uint16_t htons(uint16_t); uint16_t ntohs(uint16_t); uint32_t htonl(uint32_t); uint32_t ntohl(uint32_t);
18
TCP/IP Addresses 实际上,我们不需要处理sockaddr结构,因为我们仅仅处理一个协议族
我们可以使用sockaddr_in结构 但是,构成sockets API的C语言函数使用的是sockaddr结构类型
19
sockaddr_in sockaddr AF_INET sin_port sin_addr sin_zero Sa_family
Sa_data
20
给套接口分配地址 bind() 函数被用来给已创建的套接口分配地址. P192 int bind(); Example P193
21
bind()的使用 如下几个地方会用到 bind(): 服务器希望绑定到一个为客户端所知的地址(含端口)上
客户端可以绑定到某个特定的地址(含端口) ,也可以让操作系统为其分配任何可用的地址(含端口) P193, Tab.17.3
22
Other socket system calls
General Use closesocket() Connection-oriented (TCP) listen() connect() accept() send() recv() Connectionless (UDP) sendto() recvfrom()
23
UDP Sockets Programming
Client Server 发送数据 接收数据 连接模式
24
创建一个 UDP socket SOCKET sock; sock = socket( AF_INET, SOCK_DGRAM, 0);
if (INVALID_SOCKET==sock) { /* ERROR */ }
25
绑定到一个知名地址 (通常只需服务器执行)
SOCKET sock = socket(AF_INET,SOCK_DGRAM,0); struct sockaddr_in local; local.sin_family = AF_INET; local.sin_port = htons( 1234 ); local.sin_addr = htonl( INADDR_ANY ); bind(sock, (sockaddr *)&local, sizeof(local));
26
Sending UDP Datagrams You can send 0 bytes of data!
Sendto(); You can send 0 bytes of data! 函数的返回值说明有多少数据被操作系统接受作为报文发送——而非到达目的地的数据量 如果接收端没有收到数据的话,不会有什么错误指示
27
Receiving UDP Datagrams
如果缓冲区buf不够大,剩余的数据就永远丢失了 你可以接收0字节的数据 From中sockaddr填充的是发送端地址 调用前必须设置fromlen的值 如果from和fromlen都是空(NULL)的话,我们就不知道谁发送的数据 除非你作了特殊处理,不然调用recvfrom()不会立即返回,直到收到数据报
28
典型的UDP客户端代码 Create UDP socket. Create sockaddr with address of server.
Call sendto(), sending request to the server. No call to bind() is necessary! Possibly call recvfrom() (if we need a reply).
29
典型的UDP服务器代码 Create UDP socket and bind to well known address.
Call recvfrom() to get a request, noting the address of the client. Process request and send reply back with sendto().
30
UDP Echo Server e.g. P200 NEED TO CHECK FOR ERRORS!!! int mysock;
struct sockaddr_in myaddr, cliaddr; char msgbuf[MAXLEN]; socklen_t clilen; int msglen; mysock = socket(PF_INET,SOCK_DGRAM,0); myaddr.sin_family = AF_INET; myaddr.sin_port = htons( S_PORT ); myaddr.sin_addr = htonl( INADDR_ANY ); bind(mysock, &myaddr, sizeof(myaddr)); while (1) { len=sizeof(cliaddr); msglen=recvfrom(mysock,msgbuf,MAXLEN,0,cliaddr,&clilen); sendto(mysock,msgbuf,msglen,0,cliaddr,clilen); } NEED TO CHECK FOR ERRORS!!!
31
Connected mode P197 . A UDP socket can be used in a call to connect().
它只是简单的告诉OS对端的地址 建立连接模式并没有握手过程 在UDP套接口上调用connect()不会发送任何类型的数据
32
TCP Sockets Programming
创建一个被动模式(服务器)套接口 建立一个应用层的连接 发送/接收数据 关闭连接
33
创建一个 TCP socket SOCKET sock; sock = socket( AF_INET, SOCK_STREAM, 0);
if (INVALID_SOCKET==sock) { /* ERROR */ }
34
绑定到一个知名地址 (通常只需服务器执行)
SOCKET sock = socket(AF_INET,SOCK_STREAM,0); struct sockaddr_in local; local.sin_family = AF_INET; local.sin_port = htons( 80 ); local.sin_addr = htonl( INADDR_ANY ); bind(sock, (sockaddr *)&local, sizeof(local));
35
建立一个被动模式的TCP socket 被动模式: 地址已经确定 在指定的套接口地址上使到来的连接请求排队等待 P194
3-way handshake Listen() P193
36
接受一个到来的连接 一旦调用了listen(), the O.S. will queue incoming connections
Handles the 3-way handshake Queues up multiple connections. Accept(),P195,注意注释部分:返回一个新的套接口、并绑定了本地的网络地址与监听端口(共享<IP,PORT>)。TCP连接的标识:一对<IP,PORT>
37
关闭一个TCP连接 连接的任何一端可以调用 closesocket()
如果另外一端关闭了连接,并且缓冲区中没有数据,那么从TCP套接口读取数据将返回0,意味着EOF。P198(返回值)
38
客户端代码 TCP 可以调用 connect(),它: Connect() P196 会为客户端套接口建立一个端点地址.
无需事先调用bind(), OS会自动分配本地的端点地址 (TCP port number, IP address). 试图建立到指定服务器的连接 3-way handshake Connect() P196
39
从TCP套接口接收数据 默认情况,recv()将会阻塞直到收到数据 接收的数据量可能比缓冲区的容量要小(返回接收的字节数)
int recv(); P198 默认情况,recv()将会阻塞直到收到数据 接收的数据量可能比缓冲区的容量要小(返回接收的字节数) 必须准备好一次只接收一字节。
40
通过TCP套接口发送数据 int send(); P196 返回发送的字节数。非阻塞模式下,可能小于发送的长度。
41
Metaphor for Good Relationships Copyright Dr
Metaphor for Good Relationships Copyright Dr. Laura’s Network Programming Corp. To succeed in relationships: you need to establish your own identity. you need to be open & accepting. you need to establish contacts. you need to take things as they come, not as you expect them. you need to handle problems as they arise. bind() accept() connect() read might return 1 byte check for errors
Similar presentations