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 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> c++多线程实现网络中的进程tcp/ip通信 -> 正文阅读

[网络协议]c++多线程实现网络中的进程tcp/ip通信

socket 网络编程(windows版)

c++多线程实现网络中的进程tcp/ip通信

进程间通信(IPC)有很多种方式,但可以总结为下面4类:

  • 消息传递(管道、FIFO、消息队列)
  • 同步(互斥量、条件变量、读写锁、文件和写记录锁、信号量)
  • 共享内存(匿名的和具名的)
  • 远程过程调用(Solaris门和Sun RPC)

我们要讨论的是网络中进程之间如何通信?首要解决的问题是如何唯一标识一个进程,否则通信无从谈起!在本地可以通过进程PID来唯一标识一个进程,但是在网络中这是行不通的。其实TCP/IP协议族已经帮我们解决了这个问题,网络层的“ip地址”可以唯一标识网络中的主机,而传输层的“协议+端口”可以唯一标识主机中的应用程序(进程)。这样利用三元组(ip地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互。

客户机和服务器的进程实现网络通信的流程

图片替换文本

服务器:

  • 创建一个socket套接字,
  • 绑定监听端口;使用bind函数将客户端需要访问的ip地址和端口绑定到socket中
  • 设置监听队列;使用listen函数监听这个socket
  • 循环等待客户端的连接请求;使用accept函数和多线程接收所有的客户端发送过来的连接请求
  • 使用receive函数接收客户端发来的数据
  • 使用send函数由服务器发送数据或者资源给相应的客户机
  • close函数关闭服务端的socket

客户机:

  • 创建一个socket套接字,但这个套接字是用来储存目的IP和目的端口号的(即该客户机想要访问的某一台服务器的某一个IP地址和端口号)
  • 使用connect函数与客户端进行连接操作,
  • close函数关闭客户端的socket

下面贴cpp代码

代码使用指南:

  1. client.cpp端要求输入两个参数,第一个参数为目的ip地址,一般为127.0.0.1,第二个为端口号,固定为61717,因为server端被监听的端口号就是61717
  2. client.cpp文件有一堆是判断输入是否合法的if else分支,可以自动略过
  3. server端使用一个数组和accept方法实现等待队列,用来接收各个客户端的连接申请,同时利用多线程,处理等待队列中的客户端请求,
  4. 关于如何实现模拟多个客户端并发访问一个服务器,只需要在visual.studio中重复运行client.cpp文件即可(注意第二次开始运行时应该使用"添加新实例",否则会报错)

client.cpp

#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <WS2tcpip.h>
#include <iostream>
#include<string>
using namespace std;
#pragma comment(lib , "ws2_32.lib")

// defines the buffer size
#define BUFSIZE 4096 

// judge whether it is a number or not
bool AllisNum(string str)
{
    for (int i = 0; i < str.size(); i++)
    {
        int tmp = (int)str[i];
        if (tmp >= 48 && tmp <= 57)
        {
            continue;
        }
        else
        {
            return false;
        }
    }
    return true;
}

int main(int argc, char* argv[])
{
    WSADATA wsd;
    SOCKET sClient;
    char Buffer[BUFSIZE];
    int ret;
    struct sockaddr_in server;
    unsigned short port;
    struct hostent* host = NULL;
    // judge whether two args are legal
    if (argc < 3) {
        printf("Usage:%s IP Port \n", argv[0]);
        return -1;
    }
    int portAddr;
    if (AllisNum(argv[2]))
    {
        portAddr = atoi(argv[2]);
        if (portAddr > 65535 || portAddr < 61000 || portAddr < 0)
        {
            cout << "Invalid command line argument detected: "<< argv[2]  << endl;
            cout << "Please check your values and press any key to end the program!" << endl;
            
        }
    }
    else
    {
        cout << "Invalid command line argument detected: "<< argv[2] << endl;
        cout << "Please check your values and press any key to end the program!" << endl;
       
    }


    // load Winsock DLL
    if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0) {
        printf("Winsock    初始化失败!\n");
        
    }

    // create socket
    sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sClient == INVALID_SOCKET) {
        printf("socket() 失败: %d\n", WSAGetLastError());
    }
    // bind server listenning addr and port number
    server.sin_family = AF_INET;
    server.sin_port = htons(atoi(argv[2]));
    //server.sin_addr.s_addr = inet_addr(argv[1]);
    
    // this is for the conversion from decimal to binary
    struct in_addr inp = {};
    string ipAddr = argv[1];
    if (ipAddr == "localhost")
        inet_pton(AF_INET, "127.0.0.1", &inp);
    else
        return 3;


    server.sin_addr.s_addr = inp.S_un.S_addr;// could also use inet_pton ...

    
    // build connection with the server
    if (connect(sClient, (struct sockaddr*)&server, sizeof(server)) == SOCKET_ERROR)
    {
        printf("Failed to connect to the server at <%s> on <%d>\n"
            "Please check your values and press any key to end program!", argv[1], atoi(argv[2]));

    }
    else
    {
        // receive and send messages

        for (;;) {
            printf("%s", "Please enter a message:");
            // read data from the standard input function
            gets_s(Buffer, BUFSIZE);
            // send messages to the server
            ret = send(sClient, Buffer, strlen(Buffer), 0);
            if (ret == 0) {
                break;
            }
            else if (ret == SOCKET_ERROR) {
                printf("send() 失败: %d\n", WSAGetLastError());
                break;
            }

            // receive data from the server
            ret = recv(sClient, Buffer, BUFSIZE, 0);
            if (ret == 0) {
                break;
            }
            else if (ret == SOCKET_ERROR) {
                printf("recv() 失败: %d\n", WSAGetLastError());
                break;
            }
            Buffer[ret] = '\0';
            printf("Received: \t%s\n",  Buffer);

        }
    }
    closesocket(sClient);// close the socket
    WSACleanup();        //clean
    system("pause");
    return 0;
}

server.cpp

#include <stdio.h>  
#include <winsock2.h>  
#include <WS2tcpip.h>
#include <iostream>
#include<fstream>
#include <sstream> 
#include<string>
#include <windows.h>
#define MAXCLIENTNUM 10	
using namespace std;
#pragma comment(lib,"ws2_32.lib")  

typedef struct ClientInf
{
	SOCKET client_socket;
}ClientInf;
string host_names[4];
int counter = 0;
DWORD WINAPI Thread(LPVOID lpParameter)
{
	while (true)// loop
	{
		// receive data
		ClientInf client_inf = *(ClientInf*)lpParameter;
		char rev_data[255] = {};
		int ret = recv(client_inf.client_socket, rev_data, 255, 0);

		// resolve and handle data
		char host[NI_MAXHOST];	// Client's remote name
		char service[NI_MAXSERV]; // service(i.e.port) the client is connect on
	
		if (ret > 1)
		{
			ofstream fout("server.log", ios::app);
			rev_data[ret] = 0x00;
			cout << rev_data << endl;
			fout << rev_data << endl;
			fout.close();

		}
		
		// server informs the client that he receives data
		const char* sendData = "$message has been received by the server\r\n";

		int whetherSent = send(client_inf.client_socket, sendData, (int)strlen(sendData), 0);
		

		cout << whetherSent << endl;
		// detect disconnection
		if (whetherSent == SOCKET_ERROR )
		{
			ofstream fout("server.log", ios::app);
			fout<< "one client named "<< host_names[counter]  << " disconected" << endl;
			fout.close();
			return 0;
		}
		
	}
	return 0;
}

int main(int argc, char* argv[])
{

	//init WSA  
	WORD socketVersion = MAKEWORD(2, 2);//version of winsocket2.2

	WSADATA wsaData;

	if (WSAStartup(socketVersion, &wsaData) != 0)
	{
		return 0;
	}

	// create the socket of server
	SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

	if (slisten == INVALID_SOCKET)
	{
		printf("socket error !");
		return 2;
	}

	// bind ip addr and port number to the socket
	sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(61717);
	sin.sin_addr.s_addr = INADDR_ANY;

	// if binding failed, throw error
	if (bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)//绑定
	{
		printf("bind error!");
	}

	// if listening sth wrong, throw error  
	if (listen(slisten, 5) == SOCKET_ERROR)
	{
		return 3;
	}

	ClientInf client_inf_vector[MAXCLIENTNUM];// an array recieves all clients info
	HANDLE thread_handle_vector[MAXCLIENTNUM];// an array stores all threads 
	int client_num = 0;// the number of clients connected

	// this is the main thread that accepts all connections from clients
	while (true)
	{
		printf("waiting for connection request...\n");

		sockaddr_in remoteClient;

		int nAddrlen = sizeof(remoteClient);
		printf("current num of clients:%d\r\n", client_num);

		SOCKET c_socket = accept(slisten, (SOCKADDR*)&remoteClient, &nAddrlen);// block and wait

		if (client_num < MAXCLIENTNUM)
		{
			if (c_socket == INVALID_SOCKET)
			{
				printf("accept error!");
				continue;
			}
			client_inf_vector[client_num].client_socket = c_socket;
			char sendBuf[255] = { '\0' };
			char host[NI_MAXHOST];	// Client's remote name
			char service[NI_MAXSERV]; // service(i.e.port) the client is connect on
			ZeroMemory(host, NI_MAXHOST);
			// same as memset ( host,0,NI_MAXHOST);
			ZeroMemory(service, NI_MAXSERV); // NI_MAXSERV indicates the length of the array need filling  with 0
		
			ofstream fout("server.log", ios::app);
			if (getnameinfo((sockaddr*)&remoteClient, sizeof(remoteClient), host, NI_MAXHOST, service, NI_MAXSERV, 0) == 0)
			{
				counter = client_num;
				host_names[counter] = host;
				fout << host << " connected on port of client  " << service << endl;
				cout << host << " connected on port of client  " << service << endl;
			}
			else
			{
				inet_ntop(AF_INET, (void*)&remoteClient.sin_addr, sendBuf, sizeof(sendBuf));
				fout << host << " connected on port of client  " << service << endl;
				cout << host << " connected on port of client  " << ntohs(remoteClient.sin_port) << endl;
			}

			fout.close();
			thread_handle_vector[client_num] = CreateThread(

				NULL,
				0,
				Thread,
				&(client_inf_vector[client_num]),
				0,
				NULL

			);
			client_num++;

		}
		else
		{
			printf("connection clients are up to the upper limit:%d\r\n", client_num);
			
		}
	}

	// close all clients
	for (int i = 0; i < client_num; i++)
	{
		closesocket(client_inf_vector[i].client_socket);
	}

	closesocket(slisten);//close the server listening service

	WSACleanup();

	return 0;
}
  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-11-15 16:11:28  更:2021-11-15 16:12:57 
 
开发: 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年7日历 -2024/7/3 21:00:30-

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