win32 socket 编程(三)——TCP/IP
一、TCP/IP解析
TCP/IP协议的核心部分是传输层协议(TCP、UDP),网络层协议(IP)和物理接口层,这三层通常是在操作系统内核中实现。因此用户一般不涉及。编程时,编程界面有两种形式:
1.1、是由内核直接提供的系统调用;
1.2、使用以库函数方式提供的各种函数。
前者为核内实现,后者为核外实现。用户服务要通过核外的应用程序才能实现,所以要使用套接字(socket)来实现。
二、TCP/IP服务器及客户端操作流程
2.1服务器操作流程
2.1.1 加载套接字库。在初始化阶段调用 WSAStartup()
此函数在应用程序中初始化 Windows Sockets DLL,只有此函数调用成功后,应用程序才可以再调用其他Windows Sockets DLL 中的 API 函数。该函数原型
int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);
参数:
wVersionRequested:Socket的版本号;
WORD 类型、MAKEWORD、LOBYTE、HIBYTE 宏 ;
WORD 类型是一个 16 位的无符号整型, 在 WTYPES.H 中被定义为: typedef unsigned short WORD;
其目的是提供两个字节的存储, 在 Socket 中这两个字节可以表示主版本号和副版本号。 使用 MAKEWORD 宏可以给一个 WORD 类型赋值。例如要表示主版本号 2,副版本号 0,可以使用如下代码:
WORD wVersionRequested; wVersionRequested = MAKEWORD(, );
注意:低位内存存储主版本号2,高位内存存储副版本号0,其值为 0x0002。 使用宏 LOBYTE 可以读取 WORD 的低位字节HIBYTE 可以读取 WORD 的高位字节。 lpWSAData:指向一个用于存储 Socket 库信息的WSAStartup结构。
返回值:
a) 等于0,初始化成功;
b)不等于0, 初始化失败;
2.1.2 创建套接字 Socket
初始化 WinSockt 的动态连接库后,需要在服务器端建立一个监听的 Socket,为此可以调用 Socket()函数用来建立这个监听的 Socket,并定义此 Socket 所使用的通信协议.此函数调用成功返回 Socket 对象,失败则返回 INVALID_SOCKET.调用 WSAGetLastError()可得知原因,所有 WinSocket 的 API 函数都可以使用这个函数来获取失败的原因。函数原型如下:
SOCKET socket(int af,int type,int protocol)
参数:
a)af: 代表网络地址族,目前只有一种取值有效,即 AF_INET, 代表 internet 地址族。
b) type: 代表网络协议类型, SOCK_DGRAM 代表 UDP 协议, SOCK_STREAM 代表 TCP 协议。
c) protocol: 指定网络地址族特殊协议,目前无用,赋值0即可。
如果要建立的是遵从 TCP/IP 协议的 socket,第二个参数 type 应为 SOCK_STREAM,如为 UDP(数据报)的socket,应为 SOCK_DGRAM。sockets(套接字)编程有三种:流式套接字(SOCK_STREAM),数据报套接字(SOCK_DGRAM),原始套接字(SOCK_RAW)。基于 TCP 的 socket 编程是采用的流式套接字。
返回值:SOCKET 类型
SOCKET 是 socket 套接字类型,在 WINSOCK2.H 中有如下定义:
typedef unsigned u_int;
typedef u_int SOCKET;
可知套接字实际上就是一个无符号整形,它将被 Socket 环境管理和使用。 套接字将被创建、设置、用来发送和接收数据,最后会被关闭。
2.1.3绑定端口(blind)
将创建的套接字绑定到本机地址的某一端口上,接下来要为服务器端定义的这个监听的 Socket 指定一个地址及端口(Port),这样客户端才知道待会要连接哪一个地址的哪个端口,为此要调用 bind()函数,该函数调用成功返回 0,否则返回 SOCKET_ERROR.
int bind( SOCKET s,const struct sockaddr FAR *name,int namelen);
参 数:
a)s:被绑定的套接字
b) name: 是一个sockaddr结构指针,该结构中包含了要绑定的地址和端口。
c) namelen:第二个参数name 的长度;
如果使用者不在意地址或端口的值,那么可以设定地址为 INADDR_ANY,及 Port 为 0。对于多接口主机使用INADDR_ANY指定了一个通配地址,让该主机的任何一个IP地址都匹配。Windows Sockets会自动将其设定适当之地址及 Port(1024 到 5000 之间的值)。此后可以调用 getsockname()函数来获知其被设定的值。
下面对其涉及的类型作一番解析:
(1) sockaddr_in类型:
sockaddr_in 定义了socket发送和接收数据包的地址,其定义如下:
strucrt sockaddr_in { short sin_family; u_short sin_port; struct in_addr sin_addr; char sin_zero[]; };
其中 in_addr 定义如下:
struct in_addr { union { struct {u_char s_b1, s_b2, s_b3, s_b4} S_un_b; struct {u_short s_w1, s_w2} S_un_w; u_long S_addr; }S_un; };
首先阐述 in_addr 的信义。 很显然它是一个存储 ip 地址的联合体,有三种表达方式:
a)第一种用四个字节来表示IP地址的四个数字;
b) 第二种用两个双字节来表示IP地址;
c) 第三种用一个长整型来表示IP地址;
给 in_addr 赋值的一种最简单方法是使用 inet_addr 函数,它可以把一个代表IP地址的字符串赋值。转换为in_addr类型。如:
addrServer.sin_addr = inet_addr("192.168.0.2");
其反函数是 inet_ntoa,可以把一个 in_addr 类型转换为一个字符串。
sockaddr_in的含义比in_addr的含义要广泛,其各个字段的含义和取值如下:
a)第一字段 short sin_family,代表网络地址族,如前所述,只能取值AF_INET;
b) 第二字段 u_short sin_port,代表IP地址端口,由程序员指定;
c) 第三字段 struct in_addr sin_addr,代表IP地址;
d)第四个字段char sin_zero[8],是为了保证sockaddr_in与SOCKADDR类型的长度相等而填充进来的字段。
(2) sockaddr 类型
sockaddr 类型是用来表示 Socket 地址的类型,同 socketaddr_in 类型相比,sockaddr 的适用范围更广。
TCP/IP 地址。sockaddr 的定义如下:
struct sockaddr
{
ushort sa_family;
char sa_data[];
};
可知sockaddr 的16个字节,而sockaddr_in也有16个字节,所以sockaddr_in是可以强制类型转换为sockadddr的。事实上也往往使用这种方法。
2.1.4为套接字设置监听模式,准备客户请求。
当服务器端的 Socket 对象绑定完成之后,服务器端必须建立一个监听的队列来接收客户端的连接请求.listen()函数使服务器端的 Socket 进入监听状态,并设定可以建立的最大连接数(目前最大值限制为 5,最小值为 1).该函数调用成功返回 0,否则返回 SOCKET_ERROR。
int listen(SOCKET s,int backlog );
参 数:
a) s:需要建立监听的 Socket;
b) backlog:最大连接个数;
2.1.5 接受连接请求
当 Client 提出连接请求时,Server 端 hwnd 视窗会收到 Winsock Stack 送来自定义的一个消息,这时可以分析 lParam,然后调用相关的函数来处理此事件。为了使服务器端接受客户端的连接请求,就要使用accept()函数,该函数新建一 Socket 与客户端的 Socket 相通,原先监听之 Socket 继续进入监听状态,等待他人的连接要求。该函数调用成功返回一个新产生的 Socket 对象,否则返回 INVALID_SOCKET。
SOCKET accept(SCOKET s,struct sockaddr FAR *addr,int FAR *addrlen );
参数:
a) s: 监听套接字
b) addr:存放来连接的客户端的地址、端口信息;
c) addrlen:addr 的长度
2.1.6 用新返回的套接字和客户端进行通信。send/recv
send函数通过一个已建立连接的套接字发送数据,函数声明如下:
int send(SOCKET s, const char FAR *buf, int len, int flags);
参数:
a) s: 是一个已建立连接的套接字。
b) buf:指向一个缓冲区,该缓冲区包含将要传递的数据。
c) len:缓冲区的长度。
d) flags:收发数据方式的标识,如果不需要特殊要求可以设置为0。
调用send函数向客户端发送数据,注意这个函数使用的套接字需要使用已建立连接的那个套接字,而不是用于监听的那个套接字。
recv函数从一个已连接的套接字接收数据。函数原型如下:
int recv(SOCKET s,char FAR* buf, int len, int flags);
参数:
a) s:建立连接之后准备接收数据的那个套接字。
b) buf:指向缓冲区的指针,用来保存接收的数据。
c)len:缓冲区的长度。
d)flags:收发数据方式的标识,如果不需要特殊要求可以设置为0。
发送完数据之后还可以从客户端接收数据,这可以使用recv函数,应注意该函数的第一个参数也应该是建立连接之后的那个套接字,并且定义一个字符数组recvBuf,用来保存接收的数据。
2.1.6 关闭套接字
结束服务器和客户端的通信连接是很简单的,这一过程可以由服务器或客户机的任一端启动,只要调用closesocket()就可以了,而要关闭 Server 端监听状态的 socket,同样也是利用此函数.另外,与程序启动时调用 WSAStartup()函数相对应,程式结束前,需要调用 WSACleanup()来通知 Winsock Dll 释放 Socket 所占用的资源.这两个函数都是调用成功返回 0,否则返回 SOCKET_ERROR
int PASCAL FAR closesocket( SOCKET s );
参数:
s:Socket 的识别码;
int PASCAL FAR WSACleanup( void );
win32 socket 编程(三)——TCP/IP的更多相关文章
- 嵌入式linux的网络编程(1)--TCP/IP协议概述
嵌入式linux的网络编程(1)--TCP/IP协议概述 1.OSI参考模型及TCP/IP参考模型 通信协议用于协调不同网络设备之间的信息交换,它们建立了设备之间互相识别的信息机制.大家一定都听说过著 ...
- 计算机网络(十三),Socket编程实现TCP和UDP
十三.Socket编程实现TCP和UDP 1.TCP (1)TCPServer.java类 package com.interview.javabasic.socket; import com.int ...
- 【转载】[基础知识]【网络编程】TCP/IP
转自http://mc.dfrobot.com.cn/forum.php?mod=viewthread&tid=27043 [基础知识][网络编程]TCP/IP iooops 胖友们楼主我又 ...
- win32 socket 编程(一)——TCP/IP
一.基本概念 a) 同步:指发送方发出数据后,等收到接收方发回的响应,才发下一个数据包的通信方式. nb)异步:指的是发送方不等接收方响应,便接着发下个数据包的通信方式. c) 阻塞:指调用某函数时, ...
- win32 socket编程(二)——TCP/IP
一.大端.小端法定义 1.1小端法(Little-Endian)就是低位字节排放在内存的低地址端即该值的起始地址,高位字节排放在内存的高地址端. (主机字节顺序) 1.2 大端法(Big-Endian ...
- win32 socket编程(五)——客户端实例(TCP)
一.客户端操作流程 1.1 加载套接字库(WSAStartup()) 1.2创建套接字(socket()). 1.3向服务器发出连接请求(connect()). 对于客户端来说,它不需要绑定,可以直接 ...
- Linux系统编程(30)—— socket编程之TCP/IP协议
在世界上各地,各种各样的电脑运行着各自不同的操作系统为大家服务,这些电脑在表达同一种信息的时候所使用的方法是千差万别.就好像圣经中上帝打乱了各地人的口音,让他们无法合作一样.计算机使用者意识到,计算机 ...
- day8---多线程socket 编程,tcp粘包处理
复习下socket 编程的步骤: 服务端: 1 声明socket 实例 server = socket.socket() #括号里不写 默认地址簇使用AF_INET 即 IPv4 ...
- 2015-07学习总结——网络编程(TCP/IP)
之前学习的主要内容是单机上的处理,比如编程语言.游戏编程.数据库.多媒体编解码.其实对网络也有些接触,比如WWW.HTTP.UDP/TCP.RTP.RTMP.SNMP.FTP.单播组播.Telnet. ...
随机推荐
- python+requests接口自动化框架
为什么要做接口自动化框架 1.业务与配置的分离 2.数据与程序的分离:数据的变更不影响程序 3.有日志功能,实现无人值守 4.自动发送测试报告 5.不懂编程的测试人员也可以进行测试 正常接口测试的流程 ...
- 在asp.net 中怎样上传文件夹
以ASP.NET Core WebAPI 作后端 API ,用 Vue 构建前端页面,用 Axios 从前端访问后端 API ,包括文件的上传和下载. 准备文件上传的API #region 文件上传 ...
- 【bzoj2502】清理雪道
题目描述: 滑雪场坐落在FJ省西北部的若干座山上. 从空中鸟瞰,滑雪场可以看作一个有向无环图,每条弧代表一个斜坡(即雪道),弧的方向代表斜坡下降的方向. 你的团队负责每周定时清理雪道.你们拥有一架直升 ...
- 【CF1252J】Tiling Terrace(DP)
题意:有一个长为n的串,每个字符是#或者.中的一个,#不超过50个 有3种覆盖串的方式:(.),(..),(.#.),分别能获得g1,g2,g3的收益,覆盖之间不能重叠 第一种方式不能使用超过K次,问 ...
- 洛谷P1199 三国游戏——题解
题目传送 显然,在这样的数据范围下搜索是没希望的了.好好分析一下,发现小涵时不可能拿到与一个武将最默契的另一个武将了.所以考虑一下默契值次大的一对武将. 显然,对每一个武将来说,小涵是可以拿到默契值次 ...
- nginx做反向代理时出现302错误(转载)
现象:nginx在使用非80端口做反向代理时,浏览器访问发现返回302错误 详细现象如下: 浏览器请求登录页: 输入账号密码点击登录: 很明显登录后跳转的地址少了端口号. 原因:proxy.conf文 ...
- HTML转换PDF及SWF及图片
一.源码特点 在一些应用场景中,出于某些目的(例如需要对文章内容进行保护,禁止用户真接复制文字内容),不能直接提供HTML的方式进行浏览,那么就需要将文章内容转换为其它的格式如PDF.图 ...
- 永久关闭Linux的防火墙
重启网络服务,加载网卡配置文件systemctl restart network 清空防火墙规则iptables -F 关闭selinux防火墙vi /etc/selinux/config修改如下配置 ...
- 查看centos的版本信息
1.查看centos的版本信息 cat /etc/centos-release
- 阶段1 语言基础+高级_1-3-Java语言高级_04-集合_02 泛型_3_定义和使用含有泛型的类
创建一个类,添加一个name的属性,然后生成get和set 使用上面创建的类 使用泛型 所以我们取出来也是一个Object的类型 定义的时候规定的类型是Integer,所以这里setName设置的时候 ...