C/S模式的计算机网络通讯

程序流程:

TCP通信的server与client端的程序流程

上图中,左边是server端的,右边是client端的C++程序流程

UDP下的server和client端的程序流程

上图中,左边是server端的,右边是client端的C++程序流程

C++函数解释

根据上面的流程图,下面按步骤解释一下用程序怎么实现的,当然由于TCP 、UDP的C++源码量较大且相似度较高,所以下面只附上TCP serve的源代码并着重列出它们之间的差异:

makeword(2,2);//创建一个无符号的16位整数。
WASStartup();//异步套接字的启动函数,用于初始化套接字。
//字符数组 sendData[]:用于记录发送的次数。
socket();//原型是int socket (int domain, int type, int protocol)。用于初始化创建socket对象,成功时,返回非负数的socket描述符;失败是返回-1。
bind();//函数原型为int bind(int sockfd, const struct sockaddr* myaddr, socklen_t addrlen)。将创建的socket绑定到指定的IP地址和端口上,通常是第二个调用的socket接口。返回值:0成功,-1则出
listen();//原型为int listen(int sockfd, int backlog),listen()函数仅被TCP类型的服务器程序调用,实现监听服务,该函数的第一个参数为socket类的一个对象,第二个参数规定了套接字的连接个数。listen()成功时返回0,错误时返回-1。
accept();//原型为 int accept (int sockfd, struct sockaddr *addr, socklen_t *addrlen)。该函数仅被TCP类型的服务器程序调用,从已完成连接队列返回下一个建立成功的连接,如果已完成连接队列为空,线程进入阻塞态睡眠状态。成功时返回套接字描述符,错误时返回-1。
connetct();//原型为int connect(int sockfd, struct sockaddr *serv_addr, int addrlen)。TCP特有,用来与服务器建立一个TCP连接,实际是发起3次握手过程,连接成功返回0,连接失败返回1。
send();//原型为int send(int sockfd, const void *msg, int len, int flags)。TCP类型的数据发送。
recv();//原型为int recv(int sockfd, void *buf, int len, unsigned int flags)。TCP类型的数据接收。
sendto();//原型为int sendto(int sockfd, const void *msg, int len, unsigned int flags, const struct sockaddr *dst_addr, int addrlen)。用于非可靠连接(UDP)的数据发送,因为UDP方式未建立连接socket,因此需要制定目的协议地址。
recvfrom();//原型int recvfrom(int sockfd,void *buf, size_t len, int flags, struct sockaddr *src_addr, int*fromlen)用于非可靠连接(UDP)的数据接收。
losesocket();//关闭socket。

C++源码示例:

#include <stdio.h>
#include <winsock2.h> //包含socket类的头文件
#include<stdlib.h>
#include<time.h>  

#pragma comment(lib,"ws2_32.lib")

int main(int argc, char* argv[])
{
	//初始化WSA
	WORD sockVersion = MAKEWORD(2, 2);
	WSADATA wsaData;
	int f = 1, mode = 0;
	int ret = -1;
	char sendData[] = "Times:0000\n";
	if (WSAStartup(sockVersion, &wsaData) != 0)
	{
		return 0;
	}

	//创建套接字
	SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (slisten == INVALID_SOCKET)
	{
		printf("socket error !");
		return 0;
	}

	//绑定IP和端口
	sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(8235);
	sin.sin_addr.S_un.S_addr = INADDR_ANY;
	if (bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
	{
		printf("bind error !\n");
	}

	//开始监听
	if (listen(slisten, 5) == SOCKET_ERROR)
	{
		printf("listen error !\n");
		return 0;
	}

	//循环接收数据
	SOCKET sClient;
	sockaddr_in remoteAddr;
	int nAddrlen = sizeof(remoteAddr);
	char revData[255];
	while (f)
	{
		system("cls");
		fflush(stdin);
		printf("Wait...\n");
		sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);
		if (sClient == INVALID_SOCKET)
		{
			printf("accept error !");
			continue;
		}
		else
		{
			printf("Received a Response from: %s \r\n", inet_ntoa(remoteAddr.sin_addr));
			printf("Send(1) or Receive(0)?\n");
			scanf("%d", &mode);
			if (mode)
			{
				send(sClient, sendData, strlen(sendData), 0);
				sendData[9]++;
				if (sendData[9] == ':')
				{
					sendData[9] = '0';
					sendData[8] += 1;
				}
			}
			else
			{
				ret = recv(sClient, revData, 255, 0);
				if (ret > 0)
				{
					revData[ret] = '\0';
					printf(revData);
					printf("\n");
				}
				revData[0] = '\0';
				closesocket(sClient);
			}
		}
		printf("Continue or Quit(0)\n");
		scanf("%d", &f);
	}
	closesocket(slisten);
	WSACleanup();
	return 0;
}

程序运行现象

同样地,仍以TCP Server 为例:
在这里插入图片描述

接收字符串示例

在这里插入图片描述

发送字符串示例

注意:上面的程序可以在同一台计算机上完成(正常的话需要两台计算机),不过需要一个小工具辅助完成字符串互发并展示,该工具名为“sokit.exe”,如果需要的话,大家可以关注微信公众号“24K纯学渣”,回复“CS网络通讯”,即可获取4套(TCP-Server,TCP-Client,UDP-Server,UDP-Client)完整的C++ VS工程和小工具"sokit.exe"。

发布了25 篇原创文章 · 获赞 9 · 访问量 6197

猜你喜欢

转载自blog.csdn.net/qq_42144047/article/details/103868464