VC++ 网络编程总结(一)
1、套接字编程原理
一个完整的网间通信进程需要由两个进程组成,并且只能用同一种高层协议。也就是说,不可能通信的一段用TCP,而另一端用UDP。一个完整的网络信息需要一个五元组来标识:协议、本地地址、本地端口号、远端地址、远端端口号。
1.1Client/Server通信模型
在客户端/服务器模式中我们将请求服务的一方成为客户,将提供某种服务的一方称为服务器(Server)
一个服务程序通常在一个众所周知的地址监听对服务的请求,也就是说服务进程一直处于休眠状态,直到一个客户对这个服务的地址提出了连接请求。在这个时刻,服务程序被“惊醒”,并且为客户提供服务----对客户的请求做出适当的反应。虽然基于链接的服务是设计客户机/服务器应用程序时的标准,但有些服务也是可以通过无连接的接口提供的。
客户及/服务器的请求/响应过程示意图如下所示:

1.2Windows Sockets规范
Windows Sockets规范从90年代的1.0版本开始,经过不断的完善和发展,目前已经有了Windows Sockets 2版本。值得注意的是,Microsoft的MFC库现在只支持Windows Sockets1版本,不支持WindowsSockets2版本。
MFC提供了两个类用以封装Windows Sockets API。一个是CAsyncSocket类,它主要是提供给那些具有一定网络编程经验,希望同时拥有Socket API编程的灵活性和类库编程便利性的开发者。另一个是CSocket类,它有CAsyncSocket类派生,它具有更高的抽象化,致力于简化网络编程所需的操作。
1.3套接字
1.3.1套接字定义
套接字是一个通信终结点,它是Sockets应用程序用来在网络上发送或接收数据包的对象。套接字具有类型,与正在运行的进程相关联,并且可以有名称。目前,套接字一般只与使用网际协议组的同一“通信域”中德其他套接字交换数据。使用套接字的应用程序间通信模型如图:

1.3.2分类
1.3.2.1流式套接字
流式套接字提供没有记录边界的数据流,即字节流。字节流能确保以正确的顺序无重复地被送达。

1.3.2.2数据报套接字
数据报套接字支持面向记录的数据流,但不能确保能被送达,也无法确保按照发送顺序或不重复。

“有序”指数据包按发送的顺序送达。“不重复”指一个特定的数据包只能获取一次。这两种套接字都是双向,是可以同时在两个方向上(全双工)进行通信的数据流.
注意:在某些网络协议下(如XNS),流可以面向记录,即作为记录流而非字节流。但在更常用的TCP/IP协议下,流为字节流,Win Sockets提供与基础协议无关的抽象化级别。
1.3.3套接字的作用
套接字的作用非常大,至少在下面三种通信上下文中如此:
- 客户端/服务器模型
- 对等网络方案,如聊天应用程序
- 通过让接受应用程序将消息解释为函数调用来进行远程过程调用
1.3.4 端口与地址
在网络上,一个套接字的标识主要借助于地址和端口来描述。
套接字的地址指该套接字所在计算机的网络地址,可以为域名或IP地址的形式。通常创建套接字时不必指明网络地址,只有在拥有多个网络地址的机器时,才需要显式指定的一个网络地址。
同一机器上可以运行多个网络应用程序,每个应用程序都有自己的套接字用以进行网络通信,此时如果只有地址表示套接字,则当一个通信包到达机器时,将无法确定究竟是哪个应用程序的套接字需要接收此信息。由此增加了端口的概念,以协助区分同一机器上不同应用程序的套接字。
段开口用于标识进程,同一机器上不同的网络应用程序各有不同的端口,这样,通过“网络地址+端口号”的标识方法,便唯一标识了机器上的应用程序了。
实例应用程序:
======客户端
#include < WINSOCK2.H>
#pragma comment( lib, "WS2_32" )
#include < stdio.h> int main()
{
printf( "------------------------\n| 客户端 |\n|---------------------------------------\n" );
//------①加载动态链接库winsock DLL-----------
printf( "|加载等待中.... " );
WSADATA wsaData;
WORD wVersionRequested= MAKEWORD( 2 ,2 );
if ( WSAStartup( wVersionRequested,& wsaData)!= 0 )
{
printf( "|WSAStartup Failed\n" );
printf( "|WSAStartup Error=%d\n" , WSAGetLastError());
}
else
{
printf( "加载Winsock 库成功 |\n" );
}
printf( "|---------------------------------------\n" );
//-------②创建用于监听的流式套接口s,使用socket()-----------------
SOCKET s= socket( AF_INET, SOCK_STREAM, IPPROTO_TCP);
if ( s== INVALID_SOCKET)
{
printf( "|Failed socket\n" );
printf( "|socket Error=%d\n" , WSAGetLastError());
}
else
printf( "|已创建用于监听的套接口,套接口号:[%u]\n" , s);
printf( "|---------------------------------------\n" );
//------③本地地址bind(可以不做这部分,如果不绑定,系统将自动分配)--------
/*struct sockaddr_in Cadd;
Cadd.sin_family=AF_INET;
Cadd.sin_port=htons(4444);
Cadd.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
if (bind(s,(sockaddr*)&Cadd,sizeof(Cadd))==SOCKET_ERROR)
{
printf("|Failed bind()/n");
}*/
//-------填写要连接的服务器地址信息---------
struct sockaddr_in Sadd;
Sadd.sin_family= AF_INET;
Sadd.sin_port= htons( 5555 );
Sadd.sin_addr.S_un.S_addr= inet_addr( "127.0.0.1" );
//--------④将套接口s与远程主机相连--------------
if ( connect( s,( sockaddr*)& Sadd, sizeof ( Sadd))== INVALID_SOCKET)
{
printf( "|Failed connect()\n" );
printf( "|connect Error=%d\n" , WSAGetLastError());
}
else
{
//####################开始发接数据########################
printf( "|连接成功,可以开始发送接收数据了!\n" );
printf( "|服务器IP地址:[%s]\n 端口号:[%u]\n" , inet_ntoa( Sadd.sin_addr), ntohs( Sadd.sin_port));
//####################结束发接数据########################
}
//--------------⑤关闭套接字s,终止对动态链接库的访问----------
closesocket( s);
printf( "|---------------------------------------\n" );
printf( "|连接完毕\n" );
WSACleanup();
return 0 ;
}
========服务端
#include <winsock2.h>
#include <stdio.h>
#pragma comment(lib,"ws2_32") int main(int argc, char* argv[])
{
printf("---------\n| 服务端 |\n-----------");
//----------1、加载动态链接库Winsock Dll---------
WORD wVersionRequested = MAKEWORD(2,2);
WSADATA wsaData;
if(WSAStartup(wVersionRequested,&wsaData) != 0)
{
printf("WSAStartup Failed \n");
printf("WSAStartup Error = %d \n",WSAGetLastError());
}
else
{
printf("加载WinSocket成功 \n");
printf("调用者希望使用的WinSocket版本号=%x\n",wsaData.wVersion);
printf("加载的WinSock库支持最高WinSock版本号=%x \n",wsaData.wHighVersion);
printf("wWinSock库的说明字符串=%s \n",&wsaData.szDescription[0]);
printf("系统状态或配置信息的说明字符串=%s\n",&wsaData.szSystemStatus[0]);
}
//----------2、创建监听的流式套接口---------- SOCKET s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(s == INVALID_SOCKET)
{
printf("| Failed socket\n");
printf("| Socket Error = %d\n",WSAGetLastError());
}
else
printf("毅创建用于监听的套接口,套接口号:[%u]\n",s); //----3、绑定使用bind()
struct sockaddr_in Sadd;
Sadd.sin_family = AF_INET;
Sadd.sin_port = htons(5555);
Sadd.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
if(bind(s,(sockaddr*)&Sadd,sizeof(Sadd)) == SOCKET_ERROR)
{
printf("Failed bind()\n");
printf("Bind Error = %d\n",WSAGetLastError());
}
else
{
printf("绑定成功\n");
printf("本地Ip地址:[%s],本地端口号:[%u]\n",inet_ntoa(Sadd.sin_addr),ntohs(Sadd.sin_port));
}
//---------------④监听状态-------------
if ( listen( s, 2 )== SOCKET_ERROR)
{
printf( "Failed listen()\n" );
printf( "listen Error=%d\n" , WSAGetLastError());
}
//----------------⑤循环接受客户的连接请求---------------------------
struct sockaddr_in Cadd;
int caddLen= sizeof ( Cadd);
SOCKET c;
while ( TRUE )
{
printf( "|----------------------------\n" );
printf( "|进入监听状态.....\n|--------------------------------|\n" );
c= accept( s,( sockaddr*)& Cadd,& caddLen);
if ( c== INVALID_SOCKET)
{
printf( "|Failed accept()\n" );
printf( "|accept Error=%d\n" , WSAGetLastError());
}
else
printf( "|可以在套接口[%u]上发送接收数据了!\n" , c);
//#########################开始发送、接收###################### 注意都要在新套接口c上进行
//#########################结束发送、接收######################
closesocket( c);
printf( "|与主机IP地址是:[%s]\n|端口号是:[%u]的连接完毕\n" , inet_ntoa( Cadd.sin_addr), ntohs( Cadd.sin_port));
char xx;
printf( "|-------------------------------------\n需要退出吗?(Y\n)" );
scanf( "%c" ,& xx);
if ( xx== 'Y' || xx== 'y' )
{
break ;
}
}
closesocket( s);
WSACleanup();
return 0;
}
运行结果:


VC++ 网络编程总结(一)的更多相关文章
- vc 网络编程(socket)
在网上找了很多的资料,现将这些资料整合起来,详细介绍一下VC下的socket编程,并提供一个服务器客户端具体的实例.希望对您有所帮助 一.原理部分 (个人觉得这篇写的可以,所以转与此,原文地址:htt ...
- VC++ 网络编程总结(二)
2.基本的Windows Socket API编程 需要在程序中添加下面的包含语句:#include <winsock2.h> #pragma comment( lib, " ...
- MFC 网络编程 -- 总结
原文链接:http://www.cnblogs.com/lidabo/archive/2012/07/19/2598734.html 1.基于 TCP 的 socket 编程 /* 服务器端程序流程: ...
- VC++学习之网络编程中的套接字
VC++学习之网络编程中的套接字 套接字,简单的说就是通信双方的一种约定,用套接字中的相关函数来完成通信过程.应用层通过传输层进行数据通信时,TCP和UDP会遇到同时为多个应用程序进程提供并发服务的问 ...
- VC++网络高级编程
内含<VC网络高级编程>电子书 及源代码. 第一章.TCP/IP协议.第二章.Winsock网络编程接口:第二章.Visual C++与网络编程:第四章.基本网络编程技术:第五章.Teln ...
- Windows平台VC++ 6.0 下的网络编程学习 - 简单的测试winsock.h头文件
最近学习数据结构和算法学得有点累了(貌似也没那么累...)...找了本网络编程翻了翻当做打一个小基础吧,打算一边继续学习数据结构一边也看看网络编程相关的... 简单的第一次尝试,就大致梳理一下看书+自 ...
- windows网络编程的一些理论
参考自<VC++深入详解> 这是我在看书时记录下来的东西. 注:下面的Socket其实都应该是socket 第14章网络编程 Socket是连接应用程序与网络驱动程序的桥梁,Socket在 ...
- windows socket网络编程基础知识
下面介绍网络7层协议在WINDOWS的实现: 7层协议 WIN系统 ________________________________________ 7 应用层 7 应用程序 ____________ ...
- 完毕port(CompletionPort)具体解释 - 手把手教你玩转网络编程系列之三
手把手叫你玩转网络编程系列之三 完毕port(Completion Port)具体解释 ...
随机推荐
- (转)TCP协议那些事
(上) TCP是一个巨复杂的协议,因为他要解决很多问题,而这些问题又带出了很多子问题和阴暗面.所以学习TCP本身是个比较痛苦的过程,但对于学习的过程却能让人有很多收获.关于TCP这个协议的细节,我还是 ...
- 【转】Linux Posix Timer使用
原文网址:http://blog.csdn.net/hongszh/article/details/8608781 最强大的定时器接口来自POSIX时钟系列,其创建.初始化以及删除一个定时器的行动被分 ...
- IIS应用程序池回收图文详解
转:http://blog.sina.com.cn/s/blog_8677fcaa010138uf.html 什么是应用程序池呢?这是微软的一个全新概念:应用程序池是将一个或多个应用程序链接到一个或多 ...
- window.history
作者:zccst 旧版: forword() backword() go(number) HTML5中新增了 onhashchange 浏览器兼容性较好,用得较多 pushState / repla ...
- getDeclaredMethods()和getMethods()区别
getDeclaredMethods() 返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共.保护.默认(包)访问和私有方法, ...
- msssql 用numberic(38)替代int去解决int不够的问题
发现ms sql server的问题int(-2^31 ~ 2 ^ 31 -1)与程序中的UINT有时会对不上的时候, 发现如果用numberic(32)来做判断好像解决, 暂时就现在的插入操作来看, ...
- hdu 5407 CRB and Candies(组合数+最小公倍数+素数表+逆元)2015 Multi-University Training Contest 10
题意: 输入n,求c(n,0)到c(n,n)的所有组合数的最小公倍数. 输入: 首行输入整数t,表示共有t组测试样例. 每组测试样例包含一个正整数n(1<=n<=1e6). 输出: 输出结 ...
- LeetCode题解——Palindrome Number
题目: 判断一个数字是不是回文数字,即最高位与最低位相同,次高位与次低位相同,... 解法: 求出数字的位数,然后依次求商和求余判断是否相等. 代码: class Solution { public: ...
- kendoui-在线文本编辑器
文本编辑器用过很多,fckeditor是我之前用的最多的,但是问题也有很多,诸如安全问题,浏览器兼容问题..所以最近也一直在找替代产品,正好在研究kendo,所以就尝试了下kendo提供的edit控件 ...
- 路径 (Path)–nodejs
本模块包含一套用于处理和转换文件路径的工具集.几乎所有的方法只做字符串变换, 不会调用文件系统检查路径是否有效. 通过 require('path') 来加载此模块.以下是本模块所提供的方法: pat ...