IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> 2021-08-20 -> 正文阅读

[网络协议]2021-08-20

基于C/S的TCP/IP协议的socket编程


TCP/IP协议簇的特点:面向连接的,可靠的,基于字节流的传输协议
UDP/IP协议簇的特点:面向不连接的,不可靠的基于数据报的传输层协议

C/S模型:客户端/服务端模型。根据概念层面的,实现层面可以是任何网络。

服务端:

     1. 打开网络库
      2.检验版本
      3.创建socket
      4.绑定地址与端口(bind)
      5.开始监听
      6.创建客户端socket(accept)
      7.与客户机收发消息 (1)收(recv):得到客户端收到的参数 数据接收都是协议本身做的,
      也就是socket的底层做的系统会有一段缓冲区,储存着接受的数据      
recv的作用就是通过socket找到缓冲区,并将数据复制出来。
       (2)发(send):向目标发送数据。send的作用就是通过socket找到缓冲区,并将数据粘贴出来。

客户端

1. 打开网络库
2.检验版本
3.创建socket
4.链接到服务器(connect)
7.与服务机收发消息 (1)收(recv):得到客户端收到的参数 
(2)发(send):向目标发送数据

服务端

#include <stdio.h>
#include <stdlib.h>
#include<iostream>
#include <WinSock2.h>

using namespace std;
#pragma comment(lib,"Ws2_32.lib")

//标记
BOOL g_nFlag = TRUE;

int main(void)
{
	//打开网络库
	WORD wdVersion = MAKEWORD(1, 1);
	WSADATA wsaData;


	//int a = WSAStartup(wdVersion, &wsaData);

	//printf("外%d\n", WSAStartup(wdVersion, &wsaData));
	if (0 != WSAStartup(wdVersion, &wsaData)) // API 
	{
		printf("WSAStartup fail!");
		return -1;
	}

	//校验版本
	if (1 != HIBYTE(wsaData.wVersion) || 1 != LOBYTE(wsaData.wVersion))
	{
		printf("Version fail!");
		//关闭库
		WSACleanup();
		return -1;
	}

	//创建一个SOCKET 监听
	SOCKET socketListen = socket(AF_INET, SOCK_STREAM, 0);
	if (INVALID_SOCKET == socketListen)
	{
		printf("socket fail!");
		//关闭库
		WSACleanup();
		return -1;
	}
	//第1个参数:地址的类型。AF_INET为ipv4地址 如:192.168.1.103。4字节 32位的地址,
	//AF_INET6为ipv6地址,16字节128位的地址。
	//第2个参数:套接字类型。SOCK_STREAM 一种套接字类型,
	//提供带有OOB数据传输机制的顺序,可靠,双向,基于连接的字节流。
	//此套接字类型使用TCP作为Internet地址系列(AF_INET或AF_INET6)
	//SOCK_DGRAM 一种支持数据报的套接字类型,它是固定(通常最小)最大长度的无连接,不可靠的缓冲区。
	//此套接字使用UDP作为Internet地址系列(AF_INET或AF_INET6)
	//第3个参数:协议的类型。有IPPROTO_TCP,IPPROTO_UDP,IPPROTO_ICMP等。想要使用一个协议,
	//需要设备支持才行,参数3可以填0,系统会帮我们自动选择协议类型

	//绑定地址
	SOCKADDR_IN sockAddress;
	sockAddress.sin_family = AF_INET;
	sockAddress.sin_addr.s_addr = 16777343;
	sockAddress.sin_port = 12345;
	//端口号的本质就是一个整数,0-65535。实际:介于0-1023,为系统保留占用端口号
	//21端口分配给FTP(文件传输协议)服务。25端口分配给SMTP(简单邮件传输协议)服务。
	//80端口分配给HTTP服务。443端口为HTTPS服务。我们不能写这个范围的,我们的范围为1024-65535。

	if (SOCKET_ERROR == bind(socketListen, (struct sockaddr*) & sockAddress, sizeof(sockAddress)))
	{
		printf("bind fail!");
		//int nError = ::WSAGetLastError();
		//关闭库
		closesocket(socketListen);
		WSACleanup();
		return -1;
	}
	//bind():参数1(SOCET s):上一个函数创建了socket,绑定了协议信息(地址类型,套接字类型,协议类型)
	//参数2(const socketaddr *addr):结构体:地址类型。装IP地址,端口号
	//参数3:(int namelen)参数2的类型大小,  sizeof(参数2)
	//返回值:成功返回0,失败返回SOCKET_ERROR(具体代码可以通过int WSAGetLastError(void)获得)

	//开始监听
	if (SOCKET_ERROR == listen(socketListen, 2))
	{
	
		cout << "listen fail!" << endl;
		//关闭库
		closesocket(socketListen);
		WSACleanup();
		return -1;
	}

	//接受链接
	SOCKADDR_IN sockClient;
	int nLen = sizeof(sockClient);

	SOCKET newSocket;
	newSocket = accept(socketListen, NULL, NULL);
	//getsockname(socketListen, (struct sockaddr*)&sockClient, &nLen);
	if (INVALID_SOCKET == newSocket)
	{
		printf("listen fail!");
		//关闭库
		closesocket(socketListen);
		WSACleanup();
		return -1;
	}
     //SOCKET socketclient=accept(socketserver, NULL,NULL);
	//也可以实现,我们得到的东西不需要接收,我们直接使用socketclient。
	//想要得到信息可以使用:getpeername(socketclient,(sockaddr*)&clientMsg,&len);
	//即可以得到socketclient的clientMsg和len信息。
	//getsockname(socketserver, (sockaddr *)&clientMsg,&len)  得到本地服务器信息
	//参数1(SOCKET s):服务器端的socket,也就是socket函数创建的
	//参数2(sockaddr *addr):客户端的地址端口信息结构体(和bind的第二个参数一样,
	//意义:系统帮我们监视着客户端的信息,也就是IP地址和端口号,并通过这个结构体帮我们记录)
	//参数3(int *addrlen):参数2的大小 sizeof。
	//返回值:成功  返回值就是客户端包好的socket(与客户端通信就靠这个)。
	//失败  返回INVALID_SOCKET (具体代码可以通过int WSAGetLastError(void)获得)

	while (g_nFlag)
	{
		//判断客户端连接的集合中是否有需要接收的数据
		char szRecvBuffer[1400] = { 0 };
		char szSendBuffer[1024];
		//遍历setClient集合,如果发现setClient中的某个
		int nReturnValue = recv(newSocket, szRecvBuffer, sizeof(szRecvBuffer) - 1, 0);

		int nRes = WSAGetLastError();
		if (0 == nReturnValue)
		{
			//客户端正常关闭   服务端释放Socket
			continue;
		}
		else if (SOCKET_ERROR == nReturnValue)
		{
			//网络中断  
			printf("客户端中断连接");
			continue;
		}
		else
		{
			//接收到客户端消息 
			cout << "Client Data :" << szRecvBuffer << endl;
	//recv():参数1(SOCKET s):客户端的socket,每个客户端对应唯一的socket
	//参数2(char* buf):客户端消息的存储空间,也就是字符数组 这个一般1500字(网络传输的最大单元)
	//参数3(int len):想要读取的字节个数 一般是参数2的字节数-1,把\0字符串结尾留出来
	//参数4(int flags):数据的读取方式,填0(从系统缓冲区读出来,系统删除数据),
	//还有MSG_PEEK(从系统缓冲区读出来,系统不删除)。
	//返回值 读取字节数的大小,读没了
			
             //给客户回信
			//scanf_s ("%s", szSendBuffer, 1024);
			//getchar();
			//send(newSocket, "repeat over", strlen(szSendBuffer)+1, 0);     
			//send():参数1:目标的socket,每个客户端对应唯一的socket
	       //参数2:给对方发送的字节串(这个不要超过1500字节)
	        //参数3:字节个数 1400
	        //参数4:填0
	       //返回值 成功返回写入的字节数  执行失败  返回SOCKET_ERROR(处理:重启,等待,不用理会)

		}
	}


	//关闭socket
	closesocket(socketListen);
	closesocket(newSocket);
	//关闭网络库
	WSACleanup();

	//system("pause");
	return 0;
}

客户端

#include<winsock2.h>
#include<string>
#include<iostream>


using namespace std;
#pragma comment(lib,"ws2_32.lib")
int main()
{
	WORD wdVersion = MAKEWORD(2, 2);//版本2-2
	WSADATA wdSockMsg;
	int nRes = WSAStartup(wdVersion, &wdSockMsg);//打开网络库
	if (0 != nRes)
	{
		switch (nRes)
		{
		case WSASYSNOTREADY:
			cout << "底层网络子系统尚未准备好进行网络通信。" << endl;
			break;

		}
	}
	SOCKET socketserver = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//服务器socket
	if(INVALID_SOCKET== socketserver)
	{
		int a = WSAGetLastError();
		cout<< "创建socket失败" << endl;
		WSACleanup();
		return 0;
	}
	sockaddr_in serverMsg;
	serverMsg.sin_family = AF_INET;
	serverMsg.sin_port = 12345;
	serverMsg.sin_addr.S_un.S_addr =16777343;
	int bres = connect(socketserver, (sockaddr*)& serverMsg, sizeof(serverMsg));//链接服务器
	if (SOCKET_ERROR == bres)
	{
		cout << "链接客户端失败" << endl;
		int a = WSAGetLastError();
		closesocket(socketserver);
		WSACleanup();
		return 0;
	}
	while (1)
	{
		char szSendData[1024];
		cout << "Input Something:" << endl;
		cin >> szSendData;
		if (SOCKET_ERROR == send(socketserver, szSendData, sizeof(szSendData), 0))
		{
			cout << "send fail!" << endl;
			closesocket(socketserver);
			WSACleanup();
			return 0;
		}
	}



	//char buff[1500] = { 0 };
	//int res = recv(socketserver, buff, 1499, 0);
	//if (0 == res)
	//{
	//	cout << "客户端下线,链接中断" << endl;
	//}
	//else if (SOCKET_ERROR == res)
	//{
	//	int a = WSAGetLastError();
	//	cout << "出错了!" << endl;//根据错误码信息做相应处理(重启,等待,不用理会)
	//}
	//else
	//{
	//	cout << res << "   " << buff << endl;
	//}


	closesocket(socketserver);//关闭套接字。
	WSACleanup();//清理网络库
	system("pause");
	return 0;
}
  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-08-21 15:48:48  更:2021-08-21 15:49:35 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 20:23:27-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码