分类
常用的TCP/IP协定的3种套接字类型如下所示。流式套接字(SOCK_STREAM):
流式套接字用于提供面向连线、可靠的数据传输服务。该服务将保证数据能够实现无差错、无重複传送,并按顺序接收。流式套接字之所以能够实现可靠的数据服务,原因在于其使用了传输控制协定,即TCP(The Transmission Control Protocol)协定。
数据报套接字(SOCK_DGRAM):
数据报套接字提供了一种无连线的服务。该服务并不能保证数据传输的可靠性,数据有可能在传输过程中丢失或出现数据重複,且无法保证顺序地接收到数据。数据报套接字使用UDP(User Datagram Protocol)协定进行数据的传输。由于数据报套接字不能保证数据传输的可靠性,对于有可能出现的数据丢失情况,需要在程式中做相应的处理。
原始套接字(SOCK_RAW):
原始套接字(SOCKET_RAW)允许对较低层次的协定直接访问,比如IP、 ICMP协定,它常用于检验新的协定实现,或者访问现有服务中配置的新设备,因为RAW SOCKET可以自如地控制Windows下的多种协定,能够对网路底层的传输机制进行控制,所以可以套用原始套接字来操纵网路层和传输层套用。比如,我们可以通过RAW SOCKET来接收发向本机的ICMP、IGMP协定包,或者接收TCP/IP栈不能够处理的IP包,也可以用来传送一些自定包头或自定协定的IP包。网路监听技术很大程度上依赖于SOCKET_RAW
原始套接字与标準套接字(标準套接字指的是前面介绍的流式套接字和数据报套接字)的区别在于:原始套接字可以读写核心没有处理的IP数据包,而流式套接字只能读取TCP协定的数据,数据报套接字只能读取UDP协定的数据。因此,如果要访问其他协定传送数据必须使用原始套接字。
简介
套接字,是支持TCP/IP的网路通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的两方的一种约定,用套接字中的相关函式来完成通信过程。
非常非常简单的举例说明下:Socket=Ip address+ TCP/UDP + port。
连线方式
套用层通过传输层进行数据通信时,TCP和UDP会遇到同时为多个应用程式进程提供并发服务的问题。
主要参数
区分不同应用程式进程间的网路通信和连线,主要有3个参数:通信的目的IP位址、使用的传输层协定(TCP或UDP)和使用的连线埠号。Socket原意是 “插座”。通过将这3个参数结合起来,与一个“插座”Socket绑定,套用层就可以和传输层通过套接字接口,区分来自不同应用程式进程或网路连线的通信,实现数据传输的并发服务。
Socket可以看成在两个程式进行通讯连线中的一个端点,是连线应用程式和网路驱动程式的桥樑,Socket在应用程式中创建,通过绑定与网路驱动建立关係。此后,应用程式送给Socket的数据,由Socket交给网路驱动程式向网路上传送出去。计算机从网路上收到与该Socket绑定IP位址和连线埠号相关的数据后,由网路驱动程式交给Socket,应用程式便可从该Socket中提取接收到的数据,网路应用程式就是这样通过Socket进行数据的传送与接收的。
分类介绍
Host A上的程式A将一段信息写入Socket中,Socket的内容被Host A的网路管理软体访问,并将这段信息通过Host A的网路接口卡传送到Host B,Host B的网路接口卡接收到这段信息后,传送给Host B的网路管理软体,网路管理软体将这段信息保存在Host B的Socket中,然后程式B才能在Socket中阅读这段信息。
假设在网路中添加第三个主机Host C,那么Host A怎么知道信息被正确传送到Host B而不是被传送到Host C中了呢?基于TCP/IP网路中的每一个主机均被赋予了一个唯一的IP位址,IP位址是一个32位的无符号整数,由于没有转变成二进制,因此通常以小数点分隔,如:198.163.227.6,正如所见IP位址均由四个部分组成,每个部分的範围都是0-255,以表示8位地址。
值得注意的是IP位址都是32位地址,这是IP协定版本4(简称Ipv4)规定的,目前由于IPv4地址已近耗尽,所以IPv6地址正逐渐代替Ipv4地址,Ipv6地址则是128位无符号整数。
假设第二个程式被加入的网路的Host B中,那么由Host A传来的信息如何能被正确的传给程式B而不是传给新加入的程式呢?这是因为每一个基于TCP/IP网路通讯的程式都被赋予了唯一的连线埠和连线埠号,连线埠是一个信息缓冲区,用于保留Socket中的输入/输出信息,连线埠号是一个16位无符号整数,範围是0-65535,以区别主机上的每一个程式(连线埠号就像房屋中的房间号),低于256的连线埠号保留给标準应用程式,比如pop3的连线埠号就是110,每一个套接字都组合进了IP位址、连线埠、连线埠号,这样形成的整体就可以区别每一个套接字。
Sockets
流式套接字
本文描述流式套接字,它是两种可用的Sockets类型中的一种。(另一种类型是数据报套接字 。)
流式套接字提供没有记录边界的数据流:可以是双向的位元组流(应用程式是全双工:可以通过套接字同时传输和接收)。可依赖流传递有序的、不重複的数据。(“有序”指数据包按传送顺序送达。“不重複”指一个特定的数据包只能获取一次。)这能确保收到流讯息,而流非常适合处理大量数据。
网路传输层可将数据拆分为分组或若干个大小适当的数据包。 CSocket 类将为您处理打包和解包。
流基于显式连线:套接字 A 请求与套接字 B 建立连线;套接字 B 接受或拒绝此连线请求。
打电话的情况与流非常相似:正常情况下,接听方听到您的话和您讲话时的顺序一样,没有重複和遗漏。流套接字适合档案传输协定 (FTP) 这类实现,此协定有利于传输任意大小的 ASCII 或二进制档案。
如果必须保证数据送达而且数据大小很大时,流式套接字优于数据报套接字。有关流式套接字的更多信息,请参见Sockets规範。该规範可在 Platform SDK 中获得。
MFC 示例 CHATTER 和 CHATSRVR 都使用流式套接字。这些示例可能已经设计为使用数据报套接字向网路上的所有接收套接字广播。而目前的设计更好,这是因为:
广播模型受制于网路“洪水”(或“风暴”)问题。
后来採用的客户端-伺服器模型更有效。
流式模型提供可靠的数据传输,数据报模型则未提供。
最终模型利用在 CArchive 类借给 CSocket 类的 Unicode 和 ANSI 套接字应用程式之间通信的能力。
注意
如果使用 CSocket 类,则必须使用流。如果将套接字类型指定为 SOCK_DGRAM ,则 MFC 断言失败
Sockets 示例列表
下列 MFC 示例程式阐释了Sockets功能:
CHATTER
CHATTER 是一个套接字客户端示例应用程式。它是一个具有拆分视窗的单文档界面 (SDI) 应用程式,允许用户将讯息传送到讨论伺服器 (CHATSRVR),讨论伺服器然后将讯息同时传送给其他多个 CHATTER 用户。
通过使 CHATTER 应用程式向伺服器传送广播数据文报包而不是讯息流,可以在不使用客户端/伺服器模型的情况下编写 CHATTER 和 CHATSRVR。然而,与流式套接字不同,数据文报套接字不能保证一定会被传送;因此,一些讯息可能不会到达讨论中的所有其他用户。
运行示例
生成并运行 CHATTER 示例
打开解决方案 chatter.sln。
在“生成”选单上单击“生成”。
在“调试”选单上单击“开始执行(不调试)”。
运行 CHATTER 时,有一个“Setup”对话框请求输入以下内容:
Handle
用来定址所有讯息的名称。例如,可以选择“”。传送的所有讯息的前面都会自动加上名称“”。
Server
运行 CHATSVR 示例的计算机的 IP 地址。
Channel
标识要加入的讨论的数字(一台计算机可以运行多个讨论伺服器)。
提供了所有这些信息并单击“OK”后,主应用程式视窗随即出现。若要传送讯息,请在下部窗格中键入讯息。按 ENTER 键传送讯息。若要传送多行讯息,请按 CTRL+ENTER 键。关键字
示例
此示例说明了以下关键字:
AfxGetApp、AfxMessageBox、CArchive::Flush、CArchive::IsStoring、CControlBar::EnableDocking、CControlBar::GetBarStyle、CControlBar::SetBarStyle、CDialog::DoModal、CDocument::DeleteContents、CDocument::GetFirstViewPosition、CDocument::GetNextView、CDocument::OnNewDocument、CEditView::GetEditCtrl、CEditView::SerializeRaw、CFrameWnd::DockControlBar、CFrameWnd::EnableDocking、CFrameWnd::OnCreateClient、CFrameWnd::SetActiveView、CObject::AssertValid、CObject::Dump、CObject::IsKindOf、CObject::Serialize、CRect::Size、CSplitterWnd::CreateView、CSplitterWnd::GetPane、CStatusBar::Create、CStatusBar::SetIndicators、CString::GetBuffer、CString::GetLength、CString::IsEmpty、CString::LoadString、CString::ReleaseBuffer、CToolBar::Create、CToolBar::LoadBitmap、CToolBar::SetButtons、CView::GetDocument、CView::OnDraw、CWinApp::AddDocTemplate、CWinApp::InitInstance、CWinApp::LoadStdProfileSettings、CWinApp::OnFileNew、CWnd::DestroyWindow、CWnd::DoDataExchange、CWnd::GetClientRect、CWnd::GetWindowText、CWnd::GetWindowTextLength、CWnd::KillTimer、CWnd::OnChar、CWnd::OnCreate、CWnd::OnTimer、CWnd::PreCreateWindow、CWnd::SetTimer、CWnd::SetWindowText、SetWindowText、rand、wsprintf
注意一些示例(如此示例)尚未经过修改以反映 Visual C++ 嚮导、库和编译器的变化,但仍说明了如何完成所需的任务。
请参见
MFC 示例
CHATSRVR
CHATSRVR 是套接字伺服器示例应用程式,它是一个单文档界面 (SDI) 应用程式,用于为 CHATTER 示例的客户端实现讨论伺服器。
通过使 CHATTER 应用程式向伺服器传送广播数据文报包而不是讯息流,可以在不使用客户端/伺服器模型的情况下编写 CHATTER和 CHATSRVR。然而,与流式套接字不同,数据文报套接字不能保证一定会被传送;因此,一些讯息可能不会到达讨论中的所有其他用户。生成并运行示例
生成并运行 CHATSRVR 示例
打开解决方案 chatsrvr.sln。
在“生成”选单上单击“生成”。
在“调试”选单上单击“开始执行(不调试)”。
运行 CHATSRVR 时会显示一个请求输入“Channel”的“Discussion”对话框。“Channel”是标识要支持的讨论的数字(一台计算机可以运行多个讨论伺服器)。提供了此信息并单击“OK”后,主应用程式视窗随即出现。关键字
关键字
AfxMessageBox、CArchive::Flush、CArchive::IsStoring、CCmdUI::Enable、CCmdUI::SetText、CControlBar::EnableDocking、CControlBar::GetBarStyle、CControlBar::SetBarStyle、CDialog::DoModal、CDocument::DeleteContents、CDocument::OnNewDocument、CEditView::GetEditCtrl、CFrameWnd::DockControlBar、CFrameWnd::EnableDocking、CObject::AssertValid、CObject::Dump、CObject::Serialize、CStatusBar::Create、CStatusBar::SetIndicators、CString::GetBuffer、CString::LoadString、CString::ReleaseBuffer、CToolBar::Create、CToolBar::LoadBitmap、CToolBar::SetButtons、CView::GetDocument、CView::OnDraw、CWinApp::AddDocTemplate、CWinApp::ExitInstance、CWinApp::InitInstance、CWinApp::LoadStdProfileSettings、CWinApp::OnFileNew、CWnd::DoDataExchange、CWnd::GetWindowTextLength、CWnd::OnCreate、SetWindowText、wsprintf
注意 一些示例(如此示例)尚未经过修改以反映 Visual C++ 嚮导、库和编译器的变化,但仍说明了如何完成所需的任务。
通信
要通过Internet进行通信,至少需要一对套接字,其中一个运行在客户端,称之为ClientSocket,另一个运行于伺服器端面,称为ServerSocket。根据连线启动的方式以及本地要连线的目标,套接字之间的连线过程可以分为三个步骤:伺服器监听、客户端请求、连线确认。伺服器监听是指服务端套接字并不定位具体的客户端套接字,而是处于等待连线的状态,实时监控网路状态。
客户端请求是由客户端的套接字提出连线请求,要连线的目标是伺服器端套接字。为此,客户端的套接字必须首先描述它要连线的伺服器的套接字,指出伺服器套接字的地址和连线埠号,然后再向伺服器端套接字提出连线请求。
连线确认是当伺服器端套接字监听到或者说接收到客户端套接字的连线请求时,它就回响客户端套接字的请求,建立一个新的执行绪,把伺服器端套接字的信息传送给客户端,一旦客户端确认了此连线,连线即可建立。而伺服器端继续处于监听状态,继续接收其他客户端的连线请求。
使用套接字进行数据处理有两种基本模式:同步和异步。
同步模式:
同步模式的特点是在通过Socket进行连线、接收、传送数据时,客户机和伺服器在接收到对方回响前会处于阻塞状态,即一直等到收到对方请求才继续执行下面的语句。可见,同步模式只适用于数据处理不太多的场合。当程式执行的任务很多时,长时间的等待可能会让用户无法忍受。
异步模式:
异步模式的特点是在通过Socket进行连线、接收、传送操作时,客户机或伺服器不会处于阻塞方式,而是利用callback机制进行连线、接收、传送处理,这样就可以在调用传送或接收的方法后直接返回,并继续执行下面的程式。可见,异步套接字特别适用于进行大量数据处理的场合。
使用同步套接字进行编程比较简单,而异步套接字编程则比较複杂。



















