Socket通信
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
(三)Socket相关代码
3.1 Socket基本函数的介绍
3.1.1 创建套接字--Socket 应用程序在使用套接口通信前,必须要拥有一个套接口, 使用socket()函数来给应用程序创建一个套接口。 SOCKET socket( int af, //要使用的协议地址族 int type, //描述套接口的类型 int protocol //该套接口使用的特定协议 );
Protocol参数:说明该套接口使用的特定协议,当协议地址族af和协议
类型type确定后,协议字段可以使用的值是限定的
3.1.2 将创建的套接口与服务器地址绑定-bind()
当socket()创建了一个套接口后,需要将该套接口与该主 机上提供服务的某端口联系在一起,bind()函数用于完成 这样的绑定。 int bind( SOCKET s, //标识一个未绑定的套接口描述字 const struct sockaddr FAR * name,
的是本次创建的连接,而一个连接是包括两部分信息的,
一个是源IP和源端口,另一个是宿IP和宿端口。 (所谓accept函数,其实抽象的是TCP的连接建立过程。))
(一)Socket相关理论
所以,accept可以产生多个不同的socket,而这些socket 里包含的宿IP和宿端口是不变的,变化的只是源IP和源 端口。这样的话,这些socket宿端口就可以都是80,而
应用层程序
流套接字 接口 数据报套 接字接口
传输层 传输层
TCP
UDP IP 网络层
Socket 的 位置
数据链路层与物理层
(一)Socket相关理论
在TCP和UDP同属于传输层,共同架设在IP层(网络层)之上。 而IP层主要负责的是在节点之间(End to End)的数据包传送,这 里的节点是一台网络设备,比如计算机。因为IP层只负责把数据 送到节点,而不能区分上面的不同应用,所以TCP和UDP协议在 其基础上加入了端口的信息,端口于是标识的是一个节点上的一 个应用。除了增加端口信息,UPD协议基本就没有对IP层的数据 进行任何的处理了。而TCP协议还加入了更加复杂的传输控制, 比如滑动的数据发送窗口(Slice Window),以及接收确认和重 发机制,以达到数据的可靠传送。不管应用层看到的是怎样一个 稳定的TCP数据流,下面传送的都是一个个的IP数据包,需要由 TCP协议来进行数据重组。 所谓的端口,是为了区分不同的应用的,以在不同的IP包来到的 时候能够正确转发。
2.3 服务器与客户端五元组的建立
2.4 TCP的程序工作流程图
WSAStartup() socket() bind() listen() 等待客户连接请求的到来 accept() recv() send() closesocket() WSACleanup() 服务器端 交换数据 交换数据 关闭TCP连接 send() recv() closesocket() WSACleanup() 客户端 三次握手过程建立TCP连接 WSAStartup() socket() connect()
Socket通信
(一)Socket相关理论
Socket通信
(二)TCP的工作流程 (三)Socket相关代码
(一)Socket相关理论
提到网络编程就必须说Socket。因写网络程序就必 须要用Socket。 对于网络编程,我们也言必称TCP/IP,似乎其它网 络协议已经不存在了。对于TCP/IP,我们还知道TCP 和UDP,TCP面向连接,UDP面向无连接,前者可以 保证数据的正确和可靠性,后者则允许数据丢失。 最后,我们还知道,在建立连接前,必须知道对方 的IP地址和端口号。
在OnAccept函数中,我们添加以下代码: Socket SocketRev= new Socket (); Accept(SocketRev); 这段代码的作用是在当服务器监听到客户端的连接请求 时,新建一个CRecv的成员,并用它来接受客户端的连接 请求,也就是用它与客户端绑定。
这段代码用于接收客户端发送过来的字符串,然后以 MessageBox的形式显示出来。 最后,在主对话框的头文件中添加#include "Listen.h" , 并且声明一个CListen变量 m_listen 。然后,在主对话 框的OnInitDialog函数中,添加如下代码: m_listen.Create(8888); //8888表示的是我们要监听的端 口 m_listen.Listen();
(一)Socket相关理论
实际上,我们可以看到,防火墙并没有阻止这样的
连接,而且这是最常见的连接请求和处理方式。
为什么防火墙没有阻止这样的连接? 它是如何判定那条连接是因为connet80端口而生成的? 是不是TCP数据包里有什么特别的标志?
或者防火墙记住了什么东西?
(一)Socket相关理论—类型
(二)TCP的工作流程
2.2 客户端程序工作流程 使用WSAStartup()函数检查系统协议栈安装情况 使用socket()函数创建客户端套接口 使用connect()函数发出也服务器建立连接的请求(调用 前可以不用bind()端口号,由系统自动完成) 连接建立后使用send()函数发送数据,或使用recv()函数 接收数据 使用closesocet()函数关闭套接口 最后调用WSACleanup()函数,结束Winsock Sockets API
(一)Socket相关理论
可得出信息:
防火墙除了获取IP地址和端口号之外,并没
有足够的信息判断TCP数据包的更多信息。
所谓的端口,是为了区分不同的应用的,以
在不同的IP包来到的时候能够正确转发。
ቤተ መጻሕፍቲ ባይዱ (一)Socket相关理论
TCP/IP只是一个协议栈,就像操作系统的运行机制一 样,必须要具体实现,同时还要提供对外的操作接口, 就像操作系统会提供标准的编程接口。 TCP/IP引入了 新型的“I/O”操作---Socket编程接口 socket的出现只是可以更方便的使用TCP/IP协议栈而 已,其对TCP/IP进行了抽象,形成了几个最基本的函数 接口。比如create,listen,accept,connect,read和write 等等。
//存储了套接口的地址信息 int namelen //地址参数(name)的长度
);
bind()参数说明
S参数:标识一个未绑定的套接口描述字,它是socket()函数调用成功时返 回的值 name参数:是一个与指定协议有关的地址结构指针,存储了套接口的地址 信息,Winsock中使用sockaddr_in结构指定IP地址和端口信息 struct sockaddr_in{ short sin_family; u_short sin_port; struct in_addr sin_addr; char sin_zero[8]; } sin_family一般为AF_INET,表示使用IP地址族;sin_port是以网络字 节序表示的16位端口号;sin_addr是网络字节序的32位IP地址; sin_zero字段一般不用,用0填充 namelen参数:表示地址参数(name)的长度 IP地址参数为INADDR_ANY,则由系统内核来自动指定 port为0,则由系统自动指派一个1024~5000之间惟一的端口号
(一)Socket相关理论
如果一个socket创建后并与80端口绑定后, 是否就意味着该socket占用了80端口呢?如果 是这样的,那么当其accept一个请求后,生成 的新的socket到底使用的是什么端口呢?如果 是系统会默认给其分配一个空闲的端口号, 那一定不是80端口了,于是以后的TCP数据包 的目标端口就不是80了--防火墙一定会阻止其 通过的!
(一)Socket相关理论
我们还知道如下几个事实: 1。一个指定的端口号不能被多个程序共用。 比如,
如果鼠标占用了80端口,那么U盘就不能用80端口了。
2。很多防火墙只允许特定目标端口的数据包通过。 3。服务程序在listen某个端口并accept某个连接请求后, 会生成一个新的socket来对该请求进行处理。
(一)Socket相关理论
如果一个程序创建了一个socket,并让其监听80端口,
其实是向TCP/IP协议栈声明了其对80端口的占有。以后, 所有目标是80端口的TCP数据包都会转发给该程序(这 里的程序,因为使用的是Socket编程接口,所以首先由 Socket层来处理)。accept函数返回的新socket其实指代
服务端的建立:
添加一个基于CSocket的子类Socket,点击完成。这个类我们 用于监听。 接下来呢,我们在Socket类函数实现中点属性-重写OnAccept。点属性-重写-OnReceive。在OnReceive函数中, 我们添加以下代码: char str[100]; Receive(str,100); CString strtest; strtest=str; AfxMessageBox(strtest);
socket()参数说明
af参数:说明套接字接口要使用的协议地址族,地址族与协议族含义
相同。如果想建立一个TCP或UDP,只能用常量。AF_INET参数表示使 用互联网协议(IP)地址。Winsock还支持其他协议,但一般很少使用。
type参数:描述套接口的类型,af是AF_INET的时候只能为
SOCK_STREAM、SOCK_DGRAM或SOCK_RAW
客户端的建立
相比于服务器,客户端就简单多了,因为它只需要 一个SOCKET。 添加一个基于CSocket的子类Client,点击完成。这个 类我们用于和客户端的连接和收发数据。 然后,在主对话框的头文件中添加 #include "MySocket.h",并且声明一个Cilent 类 m_mySocket; 接着,我们得再主对话框的OnInitDialog函数中添加 m_mySocket.Creat(); //初始化SOCKET
Socket层还是能根据源/宿对来准确地分辨出IP包和
socket的归属关系,从而完成对TCP/IP协议的操作封装! 而同时,放火墙的对IP包的处理规则也是清晰明了,不 存在前面设想的种种复杂的情形。
(二)TCP的工作流程
2.1 服务器端工作流程
使用WSAStartup()函数检查系统协议栈安装情况 使用socket()函数创建服务器端通信套接口 使用bind()函数将创建的套接口与服务器地址绑定 使用listen()函数使服务器套接口做好接收连接请求准备 使用accept()接收来自客户端由connect()函数发出的连接请求 根据连接请求建立连接后,使用send()函数发送数据,或者使用recv() 函数接收数据 使用closesocket()函数关闭套接口(可以先用shutdown()函数先关闭 读写通道) 最后调用WSACleanup()函数结束Winsock Sockets API
这时候,我们可以为主对话框添加一个按钮,caption设为 “连接”,用于连接。双击这个按钮,开始函数定义,在函数 体中我们加入以下代码: m_mySocket.Connect(_T("127.0.0.1"),8888); 第一个参数表示想要连接的服务器的IP,第二个参数表示端 口。 现在,客户端与服务器的连接工作已经做好了,我们需要再 在客户端的主对话框中添加一个按钮,caption设为“发送”, 用于发送信息,在改按钮的函数中,我们添加以下代码: m_mySocket.Send("客户端发来了信息",100);//参数分别表示 要发送的字符串和字符串的最大长度.
流式套接字(SOCK_STREAM)--TCP 提供了一个面向连接、可靠的数据传输服务,数据无 差错、无重复的发送且按发送顺序接收。内设置流量 控制,避免数据流淹没慢的接收方。数据被看作是字 节流,无长度限制。 数据报套接字(SOCK_DGRAM)--UDP 提供无连接服务。数据包以独立数据包的形式被发送, 不提供无差错保证,数据可能丢失或重复,顺序发送, 可能乱序接收。