WinSockÍøÂç±à³Ì

Similar documents
Chapter #

Chap04

Chapter 5- 运输层 (5)-2017

/ / (FC 3)...

(Methods) Client Server Microsoft Winsock Control VB 1 VB Microsoft Winsock Control 6.0 Microsoft Winsock Control 6.0 1(a). 2

untitled

VoIP Make a Rtp Call VoIP Abstract... 2 VoIP RTP...3 Socket IP...9 Config Two Voice-hub

概述

FY.DOC

int *p int a 0x00C7 0x00C7 0x00C int I[2], *pi = &I[0]; pi++; char C[2], *pc = &C[0]; pc++; float F[2], *pf = &F[0]; pf++;

华清远见就业优势倍增项目手册

untitled

BOOL EnumWindows(WNDENUMPROC lparam); lpenumfunc, LPARAM (Native Interface) PowerBuilder PowerBuilder PBNI 2

W. Richard Stevens UNIX Sockets API echo Sockets TCP OOB IO C struct C/C++ UNIX fork() select(2)/poll(2)/epoll(4) IO IO CPU 100% libevent UNIX CPU IO

9 Internet 10 Internet

嵌入式Linux块设备驱动开发解析

1 Project New Project 1 2 Windows 1 3 N C test Windows uv2 KEIL uvision2 1 2 New Project Ateml AT89C AT89C51 3 KEIL Demo C C File

untitled

提问袁小兵:

IP505SM_manual_cn.doc

ebook140-8

MASQUERADE # iptables -t nat -A POSTROUTING -s / o eth0 -j # sysctl net.ipv4.ip_forward=1 # iptables -P FORWARD DROP #

untitled

穨IC-1000

UDP 8.2 TCP/IP OSI OSI 3 OSI TCP/IP IP TCP/IP TCP/IP Transport Control Protocol TCP User Datagram Protocol UDP TCP TCP/IP IP TCP TCP/IP TC

epub 61-2

ebook


Ps22Pdf

ebook140-9

ME3208E2-1.book

经华名家讲堂

Microsoft PowerPoint - os_4.ppt

Microsoft PowerPoint - Socket programming.ppt [相容模式]

Symantec™ Sygate Enterprise Protection 防护代理安装使用指南

Slide 1

, 7, Windows,,,, : ,,,, ;,, ( CIP) /,,. : ;, ( 21 ) ISBN : -. TP CIP ( 2005) 1

1 SQL Server 2005 SQL Server Microsoft Windows Server 2003NTFS NTFS SQL Server 2000 Randy Dyess DBA SQL Server SQL Server DBA SQL Server SQL Se

LSI U320 SCSI卡用户手册.doc

C6_ppt.PDF

AL-M200 Series

教育部高等学校教学

C语言的应用.PDF

Socket Programming in the Banking Collection Service Counter System

Microsoft Word - 01.DOC

软件概述

epub83-1

Microsoft Word - VC网络编程全文.doc

Basic System Administration

The Library SysLibSockets

CC213

<4D F736F F D20C9CFBAA3CAD0BCC6CBE3BBFAB5C8BCB6BFBCCAD4C8FDBCB6BFBCCAD4B4F3B8D95FBDA8D2E9B8E55F5F E646F63>

概述

目录 1 IPv6 快速转发 IPv6 快速转发配置命令 display ipv6 fast-forwarding aging-time display ipv6 fast-forwarding cache ipv6 fas

《计算机网络》实验指导书

bingdian001.com

目录 1 IPv6 快速转发 IPv6 快速转发配置命令 display ipv6 fast-forwarding aging-time display ipv6 fast-forwarding cache ipv6 fas

第壹拾篇

handsome-招股书-新规则-final-version-0422.PDF

路由器基本配置

RunPC2_.doc

51 C 51 isp 10 C PCB C C C C KEIL

上海市教育考试院关于印发新修订的

csa-faq.pdf

新・明解C言語入門編『索引』

目次 

Microsoft Word - temp71.doc

Chapter 2

Microsoft Word - CH07

<B0B8C0FDCAD6B2E15FD3A1CBA2B0E6>

Microsoft Word - MSP430 Launchpad 指导书.docx

Windows 2000 Server for T100


/3/15 1, linux. linux,,. : 1.NAT ; 2. (load balance, virtual server);; 3. ; 4. ; 5. 6.VPN; 7. ; 8. ; 9.. (,

ch09.PDF

一只特立独行的猪.doc

Transcription:

WinSock 网络编程 1. 概述 80's 初,ARPA( 美国国防部高级研究计划局 ) fi 加利福尼亚大学 Berkeley 分校提供资金,fi 开发在 UNIX 下实现 TCP/IP 协议 fi 为 TCP/IP 开发了一个 API Socket 接口 ( 套接口 ) 俗称 Bekeley 套接口模型 90's 初,Microsoft 等公司 fi 基于 Bekeley 套接口模型 fi 制定了 Windows Sockets 规范 ( 简称 WinSock) fi 已是 TCP/IP 网络的标准 1993.1,v1.1 1995.5,v2.0, 增加了 QOS ( 网络服务质量控制 ) 2. WinSock 模型提供 TCP/IP 传输层的接口 : 80 年代初, 美国国防部高级研究计划局 (ARPA) 给加利福尼亚大学 Berkeley 分校提供了资金, 让他们在 UNIX 操作系统下实现 TCP/IP 协议 在这个项目中, 研究人员为 TCP/IP 网络通信开发了一个 API( 应用程序接口 ) 这个 API 称为 Socket 接口 ( 套接字 ) 今天,SOCKET 接口是 TCP/IP 网络最为通用的 API, 也是在 INTERNET 上进行应用开发最为通用的 API 90 年代初, 由 Microsoft 联合了其他几家公司共同制定了一套 WINDOWS 下的网络编程接口, 即 WindowsSockets 规范 它是 BerkeleySockets 的重要扩充, 主要是增加了一些异步函数, 并增加了符合 Windows 消息驱动特性的网络事件异步选择机制 WINDOWS SOCKETS 规范是一套开放的 支持多种协议的 Windows 下的网络编程接口 从 1991 年的 1.0 版到 1995 年的 2.0.8 版, 经过不断完善并在 Intel Microsoft Sun SGI Informix Novell 等公司的全力支持下, 已成为 Windows 网络编程的事实上的标准 应用层 表示层 会话层 应用程序 高层 Windows Sockets API ( 动态链接库 ) 传输层网络层数据链路层物理层 网络协议栈 (TCP/IP) 网络驱动协议 网络接口卡 低层 1TCP( 传输控制协议 ) 提供虚电路和面向连接的数据流传输服务 实现无差错无重复的顺序数据传输 陈家琪 : 计算机网络 WinSock 网络编程第 1 页共 23 页

陈家琪 : 计算机网络 WinSock 网络编程第 2 页共 23 页 2UDP( 用户数据报协议 ) 提供无连接的数据报传输服务 数据通过相互独立的报文进行传输, 是无序的, 并且不保证可靠 无差错 3. WinSock DLL WinSock 与操作系统的关系 应用程序 1 应用程序 2 网络编程接口 如 WinSock API 动态链接库 网络通信协议 如 TCP/IP 协议 操作系统 如 Windows 物理通信介质 动态链接库 : 16 位版 :WINSOCK.DLL 32 位版 :WSOCK32.DLL 1DLL 装载 WinSock 服务由动态连接库 WinSock DLL 提供, 它完成 WinSock 的初始化任务, 协商 WinSock 的版本支持, 并分配必要的资源 在使用 WinSock API 之前, 必须调用 : int WSAStartup(WORD v, (LPWSADATA)&WD) 其中 : v 指示应用程序对 WinSock 版本的要求, 低字节为主版本号, 高字节为副版本号 例 :v1.1 fi v=ox0101, v2.0 fi v=ox0002, WD 返回 WinSock 的实现信息 WD 是一个 WSADATA 结构 : struct WSADATA WORD wversion; WORD whighversion; char szdescription[wsadescription_len+1]; char szsystemstatus[wsasysstatus_len+1]; 2

陈家琪 : 计算机网络 WinSock 网络编程第 3 页共 23 页 unsigned short imaxsockets; unsigned short imaxudpdg; char FAR *lpvendorinfo; ; 结构成员说明 wversion: DLL 支持的 WinSock 规范的版本 ; whighversion: DLL 可支持的 WinSock 规范的最高版本 ; szdescription: DLL 的说明及厂商描述 ; szsystemstatus: DLL 将相关的状态和配置信息 ; imaxsockets: 一个进程可以打开的最大套接口数目 ; imaxudpdg: 应用程序发送或接收的最大 UDP 数据报的大小 ; 如果应用程序没有给出限制,iMaxUdpDg 为 0( 隐含为 8192 字节 ) 最小值为 512 lpvendorinfo: 指向厂商规定数据结构的远指针 调用成功, 返回 0 2DLL 卸载当不需 WinSock DLL 的服务, 释放 DLL 所使用的资源 应用程序必须调用 : int WSACleanup() 调用成功, 返回 0 对应于每一次 WSAStartup() 调用必须有一个 WSACleanup() 调用 4. 套接口 Socket Socket 实际上是一个通信端口 ; 一个 Socket 是通讯的一端 网络通信将通过各自的 Socket 相联系 在应用开发中就像使用文件句柄一样, 应用程序向操作系统申请, 由操作系统分配本地唯一的 Socket 端口号 然后, 可以对 Socket 句柄进行读, 写操作 创建 Socket: SOCKET socket( int af, int type, // 套接口所用地址族 // 套接口类型 3

陈家琪 : 计算机网络 WinSock 网络编程第 4 页共 23 页 int protocol ) // 套接口所用协议 1af 2type 3protocol 参数 说明 AF_INET TCP/IP 地址 AF_UNIX...... UNIX 地址 SOCK_STREAM 数据流套接口, 对应 TCP 协议 SOCK_DGRAM 数据报套接口, 对应 UDP 协议............ IPPROC_TCP 使用 TCP/IP 的 TCP 协议 IPPROC_UDP 使用 TCP/IP 的 UDP 协议............ 0 1 和 2 基本确定了一种协议, 若调 用者不想指定, 设置为 0 返回值 : 若无错误发生,socket() 返回引用套接口的描述字 ( 套接口号 ) 否则的话, 返回 SOCKET_ERROR 错误, 即 -1 应用程序可通过 WSAGetLastError() 获取相应错误代码 5. 主机地址标识网络环境中的唯一通信端点标识 包含 : 协议 IP 地址 端口 ( 俗称三元组 ) 关于端口 : 在 TCP/IP 中,TCP 与 UDP 使用彼此独立的端口 ; 端口大小 :16bit( 共 2 16 个 ) 端口分为 : 1 系统全局端口 :1~1023; 例,HTTP 为 TCP/80,FTP 为 TCP/21 UDP/69,SMTP 为 TCP/25 2 系统自动分配端口 :1024~5000; 3 自由端口 :5000~65535; 6. 主机地址标识的数据结构 struct sockaddr u_short sa_family; // 协议族 char sa_data[14]; // 主机地址标识 ( 端口号 IP 地址 ) ; 4

陈家琪 : 计算机网络 WinSock 网络编程第 5 页共 23 页 struct sockaddr_in short sin_family; // 协议族 u_short sin_port; //16bit 端口号, 网络字节顺序 struct in_addr sin_addr;//32bit 的 IP 地址, 网络字节顺序 char sin_zero[8]; // 未用 ; 其中 : struct in_addr u_long s_addr; //32bit 的 IP 地址, 网络字节顺序 ; 网络字节顺序 :16 bit/32 bit 整数存放格式 高字节在前, 低字节在后 设置主机地址 void SetSockAddr(struct sockaddr_in *A,WORD Port,char *IP) A->sin_family = AF_INET; //TCP/IP 协议 A->sin_port = htons(port); // 端口号 A->sin_addr.s_addr = inet_addr(ip); //IP 地址 函数作用 htons() 把 16 bit 的数字从主机字节顺序转换到网络字节顺序 inet_addr() 把一个 IP 地址格式 "A.B.C.D" 转换成 32 bit 的网络字节顺序注 :Intel CPU 的主机字节顺序 :16 bit/32 bit 整数存放格式 低字节在前, 高字节在后 7. Socket 号与主机地址捆绑将 IP 地址和端口号与所创建的 Socket 号联系起来 int bind( SOCKET s, // 待捆绑 Socket struct sockaddr far *name, // 赋予 Socket 的主机地址标识 int len // name 的长度 ); 调用成功, 返回 0 5

陈家琪 : 计算机网络 WinSock 网络编程第 6 页共 23 页 8. WinSock 操作模式 1 同步模式或阻塞模式 (blocking mode) 采用 DOS 技术编程, 某些 WinSock 函数 ( 同步函数 ) 直到完成操作后才返回 例, 当执行数据接收函数 revc() 时, 一直等待对方发送数据, 直到接收到数据后才返回 2 异步模式或非阻塞模式 (non-blocking mode) 采用 Windows 技术编程, 利用消息 ( 事件驱动 ) 的特点, 使同步函数变为异步函数 ( 不产生阻塞 ) 关键 : 异步选择函数 WSAAsyncSelect() 的使用 WSAAsyncSelect() 可设置一个或多个网络事件消息, 如, 已收到数据 数据发送完毕 客户机请求连接 服务器已完成连接等网络事件 当设置的网络事件发生时,Windows 应用程序的窗口函数将收到一个消息 通过这个消息就可以进行相应的处理 int WSAAsyncSelect( SOCKET s, // 需要事件驱动的套接口 HWND hwnd, // 接收消息的窗口句柄 unsigned int wmsg, // 网络事件发生时的消息字 long levent // 用于指明感兴趣的网络事件集合 ); levent 参数由下表中列出的值组成 : 值 意义 FD_READ 已接收到数据 FD_WRITE 数据发送完毕 FD_OOB 已接收到边带数据 FD_ACCEPT 客户机请求连接, 用于服务器端 FD_CONNECT 服务器已完成连接, 用于客户机端 FD_CLOSE 连接关闭 ( 对方的套接口关闭 ) 例 : WSAAsyncSelect(S,hW,WM_USER+1, FD_ACCEPT FD_READ FD_CLOSE); 程序结束时, 应注销异步选择 : WSAAsyncSelect(S, hw, 0, 0); 6

陈家琪 : 计算机网络 WinSock 网络编程第 7 页共 23 页 9. 无连接协议的同步模式编程无连接服务器一般都是面向事务处理的 一个请求一个应答就完成了客户程序与服务程序之间的相互作用 1 工作过程 : 服务器 S=socket(...) bind(s,...) 客户机 S=socket(...) bind(s,...) recv(s,...) 阻塞, 等待客户请求 处理服务请求 服务请求 sendto(s,...) recv(s,...) sendto(s,...) 服务应答 阻塞, 等待服务数据处理数据 Y 继续服务? N closesocket(s) 继续? N closesocket(s) Y 无连接套接口应用程序时序图 服务器首先启动, 通过调用 socket() 建立一个套接口, 然后 bind() 将该套接口和本地地址 (IP 地址和端口 ) 联系在一起, 服务器调用 recv() 等待接收数据 客户机通过调用 socket() 建立一个套接口, 然后 bind() 将该套接口和本地地址 (IP 地址和端口 ) 联系在一起, 客户机调用 sendto() 向服务器发送数据 ; 服务器的 recv() 接收到客户机的数据后, 调用 sendto() 向客户机发送应答数据 ; 客户机的 recv() 便接收到了服务器的应答数据 ; 最后, 待数据传送结束后, 双方调用 closesocket() 关闭套接口 7

陈家琪 : 计算机网络 WinSock 网络编程第 8 页共 23 页 2 编程示例 : // UDP (TCP/IP) for the console application. // //VC6.0 add WSOCK32.LIB in Project->Settings...->Link #include "stdafx.h" #include <winsock.h> #include <stdlib.h> WORD RPort = 6666; char RIP[16]="127.0.0.1"; WORD LPort = 7777; char LIP[16]="127.0.0.1"; SOCKET S; struct sockaddr_in raddr; struct sockaddr_in laddr; //by user //by user // 远程端口 RemotePort // 远程 IP 地址 RemoteIPAddr // 本地端口 LocalPort // 本地 IP 地址 LocalIPAddr // 套接口 SOCKET // 远程参数,remoteAddr // 本地参数,localAddr WSADATA WD; //WinSock DLL 信息 int r; //result; //----------------------------------------------- void ShowInfo(char *info) puts(info); exit(1); //----------------------------------------------- void SetSockAddr(struct sockaddr_in *A,WORD Port,char *IP) A->sin_family = AF_INET; //TCP/IP 协议 A->sin_port = htons(port); // 端口 A->sin_addr.s_addr =inet_addr(ip); //IP 网址 void main() WORD v; //wversionrequested; //-- - - - - - - - Startup Win Socket - - - - - - - - v=0x0101; //0x0101 for v1.1, 0x0002 forv 2.0 r = WSAStartup(v, (LPWSADATA)&WD); if(r!= 0) ShowInfo("Start_Error"); //-- - - - - - - - Create Win Socket - - - - - - - - S = socket(pf_inet, SOCK_DGRAM, 0); if(s == -1) ShowInfo("Socket_Create_Error"); int l=sizeof(raddr); char Msg[80]; puts("type exit then Quit Program!"); SetSockAddr(lAddr, LPort, LIP); 8

陈家琪 : 计算机网络 WinSock 网络编程第 9 页共 23 页 r = bind(s,(struct sockaddr far *)&laddr, sizeof(laddr)); if(r == -1) ShowInfo("bind_Error"); SetSockAddr(&rAddr, RPort, RIP); do //-- - - - - - - - Send Mess - - - - - - - - puts("send:"); gets(msg); if(!strcmp(msg,"exit")) r = sendto(s,msg,strlen(msg), 0, (struct sockaddr far *)&raddr, l); if(r == -1) ShowInfo("Send_Error"); //-- - - - - - - - Recieve Mess - - - - - - - - puts("send ok! Waiting Recieve..."); r = recv(s, Msg, 80,0); // r = recvfrom(sd,msg,80,0,(struct sockaddr far *)&raddr, &l); // 发送套接口的主机地址信息存放在 raddr 中 if(r == -1) ShowInfo("Recieve_Error"); Msg[r]=0; puts(msg); puts("recieve ok!"); while(1); closesocket(s); WSACleanup(); return ; //----------------------------------------------- 说明 : 在 VC 中进行 WinSock API 编程开发, 需要使用到下面三个文件 : 1winsock.h WinSock API 的头文件 2wsock32.LIB WinSock API 的连接库, 把它作为项目的非缺省的连接库包含到项目文件中去 (Project -> Settings... ->Link) 3wsock32.DLL WinSock API 的动态连接库, 位于 windows 的系统目录下 (95/98:system NT: system32) int sendto( SOCKET s, char *buf, // 向一指定目的地发送数据 // 源套接口 // 待发送数据的缓冲区 int buflen, // 缓冲区中数据的长度 int flags, // 调用方式标志位, 一般取 0 struct sockaddr FAR *to, // 指向目的套接口的主机地址 int tolen // 目的套接口主机地址的长度 9

陈家琪 : 计算机网络 WinSock 网络编程第 10 页共 23 页 ); 主要用于 SOCK_DGRAM 类型套接口向 to 参数指定端的套接口发送数据报 对于 SOCK_STREAM 类型套接口,to 和 tolen 参数被忽略 ; 这种情况下 sendto() 等价于 send() int recv( SOCKET s, char *buf, // 从一个套接口接收数据 // 接收套接口 // 接收数据的缓冲区 int len, // 缓冲区中数据的长度 int flags // 调用方式标志位, 一般取 0 ); int recvfrom( SOCKET s, char *buf, // 从一个套接口接收数据 // 接收套接口 // 接收数据的缓冲区 int len, // 缓冲区中数据的长度 int flags // 调用方式标志位, 一般取 0 struct sockaddr FAR *from, // 获取发送套接口的主机地址 int fromlen ); // 发送套接口的主机地址的长度 10

陈家琪 : 计算机网络 WinSock 网络编程第 11 页共 23 页 10. 无连接协议的异步模式编程 A. 程序结构 服务器 WinMain(...) 客户机 WinMain(...) WndProc( 消息 ) WM_CREATE windows 消息处理 WndProc( 消息 ) WM_CREATE windows 消息处理 WSAStartup(...) S=socket(...) 设置本地 laddr bind(s,...,laddr) WSAStartup(...) S=socket(...) 设置服务器 raddr WSAAsyncSelect(S,..., USER+1,FD_READ) WSAAsyncSelect(S,..., USER+1,FD_READ) USER+1 FD_READ recvfrom(s,...,&raddr) 处理服务请求 sendto(s,...,raddr) 服务数据 服务请求 USER+1 FD_READ recv(s,...) 处理服务数据发送消息事件 sendto(s,...,raddr) WM_DESTROY WSAAsyncSelect( S,...,0,0) closesocket(s) WSACleanup() WM_DESTROY WSAAsyncSelect( S,...,0,0) closesocket(s) WSACleanup() return return UDP-WinSock-Windows 应用程序结构图 注 : 服务器端口 : 通过 bind(), 设置确定的服务器端口号 ; 服务器 IP 地址 : 使用本地的主机 IP 地址 ; 客户机端口 : 由操作系统自动分配 ; 可以不使用 bind() 客户机 IP 地址 : 使用本地的主机 IP 地址 ; 服务器收到客户机的服务请求时,revcfrom(S,...,&rAddr) 可获得客户机的主机地址信息 raddr, 然后, 发送 sendto(s,...,raddr) 11

陈家琪 : 计算机网络 WinSock 网络编程第 12 页共 23 页 B. 编程示例 1 服务器程序 // 服务器端口 :6666; // 服务器 IP 地址 : 使用本机的主机 IP 地址 ; // UDPSer01 (TCP/IP) for the windows application. /*VC6.0 File->New->Projects-> 选 <Win32 Application> 项 ( 输入 Project name:serverw01-> 按 OK 按钮 )-> -> 选 <a sample Win32 Application> 项 -> -> 按 Finish 按钮 -> 按 OK 按钮 ->... // //VC6.0 add WSOCK32.LIB in Project->Settings...->Link #include "stdafx.h" //VC #include <winsock.h> //by user char Title[]="UDPSer01"; // 窗口标题 HINSTANCE hinst; // current instance LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int APIENTRY WinMain(HINSTANCE hi, HINSTANCE hp, LPSTR lp, int nc) MSG msg; HWND hwnd; hinst = hi; // Store instance handle in our global variable WNDCLASS wc; memset(&wc,0,sizeof(wndclass)); wc.lpfnwndproc = (WNDPROC)WndProc; wc.hinstance = hi; wc.hicon = LoadIcon(NULL, IDI_APPLICATION); wc.hbrbackground = (HBRUSH)COLOR_WINDOW; wc.lpszclassname = "W1"; RegisterClass(&wc); // 特殊窗口 1, 始终在顶层, 任务栏显示 hwnd=createwindowex(ws_ex_topmost,"w1",title, WS_DLGFRAME WS_SYSMENU, 200,1,200,20, NULL, NULL, hi, NULL); if (!hwnd) return FALSE; ShowWindow(hWnd, nc); while(getmessage(&msg, NULL, 0, 0)) // Main message loop TranslateMessage(&msg); DispatchMessage(&msg); 12

陈家琪 : 计算机网络 WinSock 网络编程第 13 页共 23 页 return msg.wparam; WSADATA ws; SOCKET S; // 定义套接口变量 struct sockaddr_in laddr,raddr; // 本地主机地址和远程主机地址变量 int LPort=6666; // 本地端口 ( 即服务器端口 ) char LIP[]="0.0.0.0"; //IP 地址取本机的主机 IP 地址 ( 若多个, 都有效 ) char Msg[88]; int d,l=sizeof(raddr); void SetSockAddr(struct sockaddr_in *A,WORD Port,char *IP) A->sin_family = AF_INET; //TCP/IP 协议 A->sin_port = htons(port); // 端口 A->sin_addr.s_addr =inet_addr(ip); //IP 网址 // 消息处理 LRESULT CALLBACK WndProc(HWND hw, UINT msg, WPARAM wp, LPARAM lp) switch (msg) case WM_DESTROY: WSAAsyncSelect(S, hw, 0, 0); // 注销网络异步选择事件消息 closesocket(s); // 关闭套接口 WSACleanup(); // 卸载网络动态链接库 PostQuitMessage(0); // 向窗口发送程序退出消息 case WM_CREATE: WSAStartup(0x0101,&ws); // 装载网络动态链接库 S=socket(AF_INET, SOCK_DGRAM,0); // 创建套接口 SetSockAddr(&lAddr,LPort,LIP); // 设置本地主机地址参数 bind(s,(struct sockaddr *)&laddr,sizeof(laddr)); // 捆绑本地主机地址 WSAAsyncSelect(S,hW,WM_USER+1,FD_READ); // 注册网络异步选择事件消息 case WM_USER+1: switch(loword(lp)) case FD_READ: d=recvfrom(s, Msg,sizeof(Msg), 0, // 接收客户机信息 (struct sockaddr *)&raddr, &l); // Msg= 接收到的信息,d= 接收到的字符数, 13

陈家琪 : 计算机网络 WinSock 网络编程第 14 页共 23 页 // raddr= 客户机的主机地址 Msg[d]=0; char buf[88]; wsprintf(buf,"from Client:%s",Msg); SetWindowText(hW,buf); // 在窗口标题栏显示接收的信息 // 把接收的信息发回给客户机 sendto(s, Msg, strlen(msg), 0, (struct sockaddr *) &raddr, l); return DefWindowProc(hW, msg, wp, lp); 2 客户机程序 // 客户机端口 : 由操作系统自动分配 ; // 客户机 IP 地址 : 使用本机的主机 IP 地址 ; // UDPCli01 (TCP/IP) for the windows application. // //VC6.0 add WSOCK32.LIB in Project->Settings...->Link #include "stdafx.h" //VC #include <winsock.h> //by user char Title[]="UDPCli01"; // 窗口标题 HINSTANCE hinst; // current instance LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int APIENTRY WinMain(HINSTANCE hi, HINSTANCE hp, LPSTR lp, int nc) MSG msg; HWND hwnd; hinst = hi; // Store instance handle in our global variable WNDCLASS wc; memset(&wc,0,sizeof(wndclass)); wc.lpfnwndproc = (WNDPROC)WndProc; wc.hinstance = hi; wc.hicon = LoadIcon(NULL, IDI_APPLICATION); wc.hbrbackground = (HBRUSH)COLOR_WINDOW; wc.lpszclassname = "W1"; RegisterClass(&wc); // 特殊窗口 1, 始终在顶层, 任务栏显示 hwnd=createwindowex(ws_ex_topmost,"w1",title, WS_DLGFRAME WS_SYSMENU, 14

陈家琪 : 计算机网络 WinSock 网络编程第 15 页共 23 页 400,1,200,40, NULL, NULL, hi, NULL); if (!hwnd) return FALSE; ShowWindow(hWnd, nc); while(getmessage(&msg, NULL, 0, 0)) // Main message loop TranslateMessage(&msg); DispatchMessage(&msg); return msg.wparam; WSADATA ws; SOCKET S; // 定义套接口变量 struct sockaddr_in raddr; // 远程主机地址变量 int RPort=6666; // 远程服务器端口 char RIP[16]="127.0.0.1"; // 远程服务器 IP 地址 char Msg[88]; int d,l=sizeof(raddr); void SetSockAddr(struct sockaddr_in *A,WORD Port,char *IP) A->sin_family = AF_INET; //TCP/IP 协议 A->sin_port = htons(port); // 端口 A->sin_addr.s_addr =inet_addr(ip); //IP 网址 // 消息处理 LRESULT CALLBACK WndProc(HWND hw, UINT msg, WPARAM wp, LPARAM lp) switch (msg) case WM_DESTROY: WSAAsyncSelect(S, hw, 0, 0); // 注销网络异步选择事件消息 closesocket(s); // 关闭套接口 WSACleanup(); // 卸载网络动态链接库 PostQuitMessage(0); // 向窗口发送程序退出消息 case WM_CREATE: WSAStartup(0x0101,&ws); // 装载网络动态链接库 S=socket(AF_INET, SOCK_DGRAM,0); // 创建套接口 SetSockAddr(&rAddr,RPort,RIP); // 设置远程服务器主机地址参数 WSAAsyncSelect(S,hW,WM_USER+1,FD_READ); // 注册网络异步选择事件消息 15

陈家琪 : 计算机网络 WinSock 网络编程第 16 页共 23 页 case WM_USER+1: switch(loword(lp)) case FD_READ: d=recv(s,msg,sizeof(msg),0); // 接收服务器数据 Msg[d]=0; char buf[88]; wsprintf(buf,"from Server:%s",Msg); SetWindowText(hW,buf); // 在窗口标题栏显示接收的信息 case WM_LBUTTONDOWN: // 鼠标左键按下 wsprintf(msg,"hello!"); // 发送 "Hello!" sendto(s,msg,strlen(msg),0,(struct sockaddr *)&raddr,l); case WM_RBUTTONDOWN: // 鼠标右键按下 wsprintf(msg,"hi!"); // 发送 "Hi!" sendto(s,msg,strlen(msg),0,(struct sockaddr *)&raddr,l); return DefWindowProc(hW, msg, wp, lp); 16

陈家琪 : 计算机网络 WinSock 网络编程第 17 页共 23 页 11. 面向连接协议的同步模式编程 工作过程 : 服务器首先启动, 通过调用 socket() 建立一个套接口, 然后 bind() 将该套接口和本地地址 (IP 地址和端口 ) 联系在一起, 再 listen() 使套接口做好侦听的准备, 并规定它的请求队列的长度, 之后就调用 accept() 来接收连接, 并获得客户机的地址信息 ; 客户在建立套接口后就可调用 connect() 和服务器建立连接 ; 连接一旦建立, 客户机和服务器之间就可以通过调用 : send() 和 recv() ( 或 read() 和 write()) 来发送和接收数据 ; 最后, 待数据传送结束后, 双方调用 closesocket() 关闭套接口 服务器 socket() bind() listen() 阻塞, 等待客户连接 accept() 连接请求 客户机 socket() connect() recv() 阻塞, 等待客户请求 处理服务请求 服务请求 send() recv() send() 服务应答 阻塞, 等待服务数据处理数据 Y 继续服务? N close(socket) 继续? N closesocket() Y 面向连接套接口应用程序时序图 17

陈家琪 : 计算机网络 WinSock 网络编程第 18 页共 23 页 12. 面向连接协议的异步模式编程 A. 程序结构 服务器 客户机 WinMain(...) WinMain(...) WndProc( 消息 ) WM_CREATE windows 消息处理 WndProc( 消息 ) WM_CREATE windows 消息处理 WSAStartup(...) Ss=socket(...) 设置本地 SA bind(ss,...,sa) WSAAsyncSelect(S,...,USER+1, FD_ACCEPT...) lisen(ss,...) WSAStartup(...) Cs=socket(...) 设置服务器 SA WSAAsyncSelect(S,...,USER+1, FD_READ...) Ss=connect(Cs,...,SA) USER+1 FD_ACCEPT Cs=accept(Ss,...,&CA) 处理连接请求 send(cs,...) FD_ READ recv(cs,...) 处理服务请求 send(cs,...) FD_CLOSE 得知客户机断开连接 WM_DESTROY WSAAsyncSelect( S,...,0,0) closesocket(s) WSACleanup() 服务数据 服务请求 USER+1 FD_CONNECT 得知连接到服务器 FD_READ recv(,...) 处理服务数据 FD_CLOSE 得知服务器断开连接发送消息事件 send(cs,...) WM_DESTROY WSAAsyncSelect( S,...,0,0) closesocket(s) WSACleanup() return return TCP-WinSock-Windows 应用程序结构图 18

陈家琪 : 计算机网络 WinSock 网络编程第 19 页共 23 页 2. 编程示例 : 1 服务器程序 // TCP-Server (TCP/IP) for the windows application. /*VC6.0 File->New->Projects-> 选 <Win32 Application> 项 ( 输入 Project name:serverw01-> 按 OK 按钮 )-> -> 选 <a sample Win32 Application> 项 -> -> 按 Finish 按钮 -> 按 OK 按钮 ->... */ //VC6.0 add WSOCK32.LIB in Project->Settings...->Link #include "stdafx.h" //VC #include <winsock.h> //by user char Title[]=" TCPServer "; // 窗口标题 HINSTANCE hinst; // current instance LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int APIENTRY WinMain(HINSTANCE hi,hinstance hp,lpstr lp,int nc) MSG msg; HWND hwnd; hinst = hi; //Store instance handle in our global variable WNDCLASS wc; memset(&wc,0,sizeof(wndclass)); wc.lpfnwndproc = (WNDPROC)WndProc; wc.hinstance = hi; wc.hicon = LoadIcon(NULL, IDI_APPLICATION); wc.hbrbackground = (HBRUSH)COLOR_WINDOW; wc.lpszclassname = "W1"; RegisterClass(&wc); // 特殊窗口 1, 始终在顶层, 任务栏显示 hwnd=createwindowex(ws_ex_topmost,"w1",title, WS_DLGFRAME WS_SYSMENU, 400,1,200,40, NULL, NULL, hi, NULL); if(!hwnd) return FALSE; ShowWindow(hWnd, nc); // Main message loop: while (GetMessage(&msg, NULL, 0, 0)) TranslateMessage(&msg); DispatchMessage(&msg); return msg.wparam; 19

陈家琪 : 计算机网络 WinSock 网络编程第 20 页共 23 页 WSADATA ws; SOCKET Ss,Cs; // 服务器和客户机的套接口变量 struct sockaddr_in SA,CA; // 服务器和客户机的主机地址变量 WORD SPort = 6666; // 本机端口 ( 服务器 ) char SIP[16]="127.0.0.1"; // 本机 IP 地址 ( 服务器 ) char Msg[88]; int d,l=sizeof(ca); void SetSockAddr(struct sockaddr_in *A,WORD Port,char *IP) A->sin_family = AF_INET; //TCP/IP 协议 A->sin_port = htons(port); // 端口 A->sin_addr.s_addr =inet_addr(ip); //IP 网址 // 消息处理 LRESULT CALLBACK WndProc(HWND hw,uint msg, WPARAM wp,lparam lp) switch (msg) case WM_CREATE: // 消息 : 产生窗口 WSAStartup(0x0101,&ws); Ss=socket(AF_INET, SOCK_STREAM,0); // 创建套接口 ( 流式 ) SetSockAddr(&SA,SPort,SIP); // 设置服务器主机地址 bind(ss,(struct sockaddr *)&SA,sizeof(SA));// 捆绑主机地址 // 向 windows 注册套接口 Ss 所产生的网络消息事件 WSAAsyncSelect(Ss,hW,WM_USER+1, FD_ACCEPT FD_READ FD_CLOSE); listen(ss,5); // 监听客户机连接请求 case WM_DESTROY: // 消息 : 关闭窗口 WSAAsyncSelect(Ss, hw, 0, 0); // 注销套接口 Ss 的消息事件 closesocket(ss); // 关闭套接口 Ss WSACleanup(); // 卸载 WinSock DLL PostQuitMessage(0); // 向 windows 发送退出程序的消息 case WM_USER+1: switch(loword(lp)) case FD_ACCEPT: Cs=accept(Ss,(struct sockaddr *)&CA,&l); wsprintf(msg,"s:welcome!"); send(cs, Msg,strlen(Msg),0); case FD_READ: // 获取客户机主机地址 // 向客户机发送连接应答 20

陈家琪 : 计算机网络 WinSock 网络编程第 21 页共 23 页 d=recv(wp,msg,sizeof(msg),0); // 接收客户机服务请求,wP=Cs Msg[d]=0; SetWindowText(hW, Msg); // 在窗口标题栏显示服务请求 send(wp, Msg,strlen(Msg),0); // 向客户机发送服务数据 case FD_CLOSE: wsprintf(msg,"client leave! [%d]",wp); SetWindowText(hW, Msg); // 在窗口标题栏显示信息 return DefWindowProc(hW,msg,wP,lP); 2 客户机程序 // TCP-Client (TCP/IP) for the windows application. // //VC6.0 add WSOCK32.LIB in Project->Settings...->Link #include "stdafx.h" #include <winsock.h> //by user char Title[]="TCPClient"; // 窗口标题 HINSTANCE hinst; // current instance LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int APIENTRY WinMain(HINSTANCE hi,hinstance hp,lpstr lp,int nc) MSG msg; HWND hwnd; hinst = hi; //Store instance handle in our global variable WNDCLASS wc; memset(&wc,0,sizeof(wndclass)); wc.lpfnwndproc = (WNDPROC)WndProc; wc.hinstance = hi; wc.hicon = LoadIcon(NULL, IDI_APPLICATION); wc.hbrbackground = (HBRUSH)COLOR_WINDOW; wc.lpszclassname = "W1"; RegisterClass(&wc); // 特殊窗口 1, 始终在顶层, 任务栏显示 hwnd=createwindowex(ws_ex_topmost,"w1",title, WS_DLGFRAME WS_SYSMENU, 400,1,200,40, NULL, NULL, hi, NULL); if(!hwnd) return FALSE; 21

陈家琪 : 计算机网络 WinSock 网络编程第 22 页共 23 页 ShowWindow(hWnd, nc); // Main message loop: while (GetMessage(&msg, NULL, 0, 0)) TranslateMessage(&msg); DispatchMessage(&msg); return msg.wparam; WSADATA ws; SOCKET Ss,Cs; // 服务器和客户机的套接口变量 struct sockaddr_in SA,CA; // 服务器和客户机的主机地址变量 WORD SPort = 6666; // 远程服务器端口 char SIP[16]="127.0.0.1"; // 远程服务器 IP 地址 char Msg[88]; int d,l=sizeof(ca); void SetSockAddr(struct sockaddr_in *A,WORD Port,char *IP) A->sin_family = AF_INET; //TCP/IP 协议 A->sin_port = htons(port); // 端口 A->sin_addr.s_addr =inet_addr(ip); //IP 网址 // 消息处理 LRESULT CALLBACK WndProc(HWND hw,uint msg, WPARAM wp,lparam lp) switch (msg) case WM_CREATE: WSAStartup(0x0101,&ws); Cs=socket(AF_INET,SOCK_STREAM,0); // 创建套接口 ( 流式 ) SetSockAddr(&SA,SPort,SIP); // 服务器主机地址 ( 远程 ) WSAAsyncSelect(Cs,hW,WM_USER+1, FD_CONNECT FD_READ FD_CLOSE); connect(cs,(struct sockaddr *)&SA, sizeof(sa)); // 连接服务器 case WM_DESTROY: // 消息 : 关闭窗口 WSAAsyncSelect(Cs, hw, 0, 0); // 注销套接口 Cs 的消息事件 closesocket(cs); // 关闭套接口 Cs WSACleanup(); // 卸载 WinSock DLL PostQuitMessage(0); // 向 windows 发送退出程序的消息 case WM_USER+1: 22

陈家琪 : 计算机网络 WinSock 网络编程第 23 页共 23 页 switch(loword(lp)) case FD_CONNECT: SetWindowText(hW," 已连接到服务器!");// 在窗口标题栏显示信息 case FD_READ: d=recv(wp,msg,sizeof(msg),0); // 接收服务器的服务数据, //wp=cs Msg[d]=0; SetWindowText(hW, Msg); // 在窗口标题栏显示服务数据 case FD_CLOSE: wsprintf(msg,"server Stop! [%d]",wp); SetWindowText(hW, Msg); // 在窗口标题栏显示信息 case WM_LBUTTONDOWN: // 消息 : 鼠标左键按下 wsprintf(msg,"hello!"); send(cs, Msg,strlen(Msg),0); // 向服务器发送服务请求 "Hello!" case WM_RBUTTONDOWN: // 消息 : 鼠标右键按下 wsprintf(msg,"hi!"); send(cs, Msg,strlen(Msg),0); // 向服务器发送服务请求 "Hi!" return DefWindowProc(hW,msg,wP,lP); 23