第14章 网络编程 VS2013 VC++深入详解 孙鑫

版权声明:版权所有,盗版必究。欢迎转载收藏。 https://blog.csdn.net/yl_best/article/details/83349448

目录

14.1 计算机网络基本知识

14.1.7 TCP/IP模型

14.1.8 端口

14.1.10 网络字节顺序

sockets(套接字)编程有三种,

TCP流式套接字的编程步骤

​​​​​​​服务器端程序:

​​​​​​​客户端程序:

UDP型套接字

服务器端(接收端)程序:

​​​​​​​客户端(发送端)程序:

​​​​​​​扩展阅读:

TCP程序代码实现

新建项目

代码

TcpSrv.cpp

TcpClient.cpp

程序执行画面

14.6基于UDP的简单聊天程序


14.1 计算机网络基本知识

14.1.7 TCP/IP模型

面试常考OSI七层参考模型

TCP/IP模型

OSI参考模型

Function

应用层

应用层

处理网络应用

表示层

数据表示

会话层

主机间通信

传输层

传输层

端到端的连接

网络层

网络层

寻址和最短路径

网络接口

数据链路层

介质访问(接入)

物理层

二进制传输

 

14.1.8 端口

1. 端口使用一个16位的(二进制)数字来表示,范围0~65535(0XFFFF),1024以下的端口号保留给预定义的服务,如http使用端口80。我们在编写网络应用程序时,要为程序指定1024以上的端口号。

14.1.10 网络字节顺序

1. 基于Intel的CPU,我们常用的PC机采用的是低位先存。为保证数据的正确性,在网络协议中需要指定网络字节顺序,TCP/IP协议使用16位整数和32位整数的高位先存格式。 

2. 网络中不同主机间进行通信时,要统一采用网络字节顺序。

​​​​​​​sockets(套接字)编程有三种,

流式套接字(SOCK_STREAM),数据报套接字(SOCK_DGRAM),原始套接字(SOCK_RAW);基于TCP的socket编程是采用的流式套接字(SOCK_STREAM)。基于UDP采用的数据报套接字(SOCK_DGRAM).

TCP流式套接字的编程步骤

VS2013: Linker -> Input->Additional Dependencies->输入ws2_32.lib

​​​​​​​服务器端程序:

1、加载套接字库

2、创建套接字(socket)。

3、将套接字绑定到一个本地地址和端口上(bind)。

4、将套接字设为监听模式,准备接收客户请求(listen)。

5、等待客户请求到来;当请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept)。

6、用返回的套接字和客户端进行通信(send/recv)。

7、返回,等待另一客户请求。

8、关闭套接字。

​​​​​​​客户端程序:

1、加载套接字库

2、创建套接字(socket)。

3、向服务器发出连接请求(connect)。

4、和服务器端进行通信(send/recv)。

5.关闭套接字。

UDP型套接字

服务器端(接收端)程序:

1、创建套接字(socket)。

2、将套接字绑定到一个本地地址和端口上(bind)。

3、等待接收数据(recvfrom)。

4、关闭套接字。

​​​​​​​客户端(发送端)程序:

1、创建套接字(socket)。

2、向服务器发送数据(sendto)。

3、关闭套接字。

​​​​​​​扩展阅读:

为什么qq用的UDP为主,而TCP为辅助

https://blog.csdn.net/pmt123456/article/details/55216555

TCP程序代码实现

新建项目

在当前项目TcpSrvs中添加TcpClient project

代码

TcpSrv.cpp

#include <winsock2.h>

#include <stdio.h>

void main()

{
	//Load socket library
	WORD wVersionRequested;//版本号

	WSADATA wsaData;

	int err;

	wVersionRequested = MAKEWORD(1, 1);//1.1版本的套接字



	err = WSAStartup(wVersionRequested, &wsaData);

	if (err != 0)

	{

		return;

	}//加载套接字库,如果失败返回0

	if (LOBYTE(wsaData.wVersion) != 1 ||

		HIBYTE(wsaData.wVersion) != 1)

	{

		return;

	}//判断高低字节是不是1,如果不是1.1的版本则退出



	//创建流式套接字,基于TCP(SOCK_STREAM)

	SOCKET socSrv = socket(AF_INET, SOCK_STREAM, 0);

	//Socket地址结构体的创建

	SOCKADDR_IN addrSrv;

	addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//转换Unsigned long型为网络字节序格式

	addrSrv.sin_family = AF_INET;//指定地址簇

	addrSrv.sin_port = htons(6000);

	//指定端口号,除sin_family参数外,其它参数都是网络字节序,因此需要转换



	//将套接字绑定到一个端口号和本地地址上

	bind(socSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));


	//listen mode, ready for client request
	listen(socSrv, 5);

	SOCKADDR_IN addrClient;//字义用来接收客户端Socket的结构体

	int len = sizeof(SOCKADDR);//初始化参数,这个参数必须进行初始化



	//循环等待接受客户端发送请求

	while (1)

	{

		//等待客户请求到来;当请求到来后,接受连接请求,

		//返回一个新的对应于此次连接的套接字(accept)。

		//此时程序在此发生阻塞

		SOCKET sockConn = accept(socSrv, (SOCKADDR*)&addrClient, &len);



		char sendBuf[100];

		sprintf(sendBuf, "Welcome %s to http://sunxin.org",

			inet_ntoa(addrClient.sin_addr));//格式化输出

		//用返回的套接字和客户端进行通信

		send(sockConn, sendBuf, strlen(sendBuf) + 1, 0);//多发送一个字节



		//接收数据

		char recvBuf[100];

		recv(sockConn, recvBuf, 100, 0);

		printf("%s\n", recvBuf);

		closesocket(sockConn);

	}

}

TcpClient.cpp

#include <winsock2.h>

#include <stdio.h>

void main()

{

	WORD wVersionRequested;//版本号

	WSADATA wsaData;

	int err;

	wVersionRequested = MAKEWORD(1, 1);//1.1版本的套接字



	err = WSAStartup(wVersionRequested, &wsaData);

	if (err != 0)

	{

		return;

	}//加载套接字库,如果失败返回0

	if (LOBYTE(wsaData.wVersion) != 1 ||

		HIBYTE(wsaData.wVersion) != 1)

	{

		return;

	}//判断高低字节是不是1,如果不是1.1的版本则退出 

	//创建流式套接字,基于TCP(SOCK_STREAM)

	SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0);

	//Socket地址结构体的创建

	SOCKADDR_IN addrSrv;

	addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//转换字符型为网络字节序格式

	addrSrv.sin_family = AF_INET;//指定地址簇

	addrSrv.sin_port = htons(6000);

	//指定端口号,除sin_family参数外,其它参数都是网络字节序,因此需要转换



	connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));

	char recvBuf[100];//和服务器端进行通信(send/recv)。

	recv(sockClient, recvBuf, 100, 0);

	printf("%s\n", recvBuf);

	send(sockClient, "This is lisi", strlen("This is lisi") + 1, 0);



	closesocket(sockClient);//关闭套接字。

	WSACleanup();//必须调用这个函数清除参数

}

程序执行画面

先执行服务器端,再执行客户端。客户端可以多次关闭打开。

14.6基于UDP的简单聊天程序

对于聊天程序来说,即使丢失一些数据,也不会影响信息的交流,可以根据上下文的情况,知道对方所要表达的意思,或者根据对方的信息,重新发送我们所说的话。对于TCP来说,在通信前,需要经过三步握手协议以建立连接,而建立连接的过程往往是比较耗费时间的。连接建立后,在聊天过程中,可能经过好长一段时间,聊天的双方才会说一句话,那么连接是应该保持还是先断开,等对方说话时再建立连接呢?也就是说,TCP协议的面向连接、数据确认和重传机制将会影响聊天的效率。所以,对于聊天类的软件来说,通常都采用基于UDP的方式来实现。这种方式的特点是不需要建立连接,也没有数据确认和重传机制,因此实时性较高。

来源: VC++深入详解 孙鑫

猜你喜欢

转载自blog.csdn.net/yl_best/article/details/83349448