Network programming and multithreading model under Windows

Socket programming

In order for the client and server to communicate over the network, Socketprogramming .

The server first calls the socket()function to create the network protocol as IPv4and the transmission protocol as TCP, Socketand then calls the bind()function to Socketbind an IPaddress and port to this . Then, the server can call the listen()function to monitor. After entering the monitoring state, accept()it can obtain the client's connection from the kernel by calling the function. If there is no client connection, it will block and wait for the arrival of the client connection.

SocketAfter the client is created , it calls connect()the function to initiate a connection. The parameters of the function should specify the IPaddress and port number of the server, and then start the three-way handshake .

During the TCPconnection process, the server's kernel actually Socketmaintains two queues for each :

  • semi-join queue
  • fully connected queue

When TCPthe fully connected queue is not empty, the server-side accept()function will take out a completed connection from the TCPfully Socketreturn to the application, which will be used for subsequent data transmission Socket. Therefore, the three-way handshake Socketand the transmission of data Socketare not the same.

After the connection is established, the client and the server begin to transmit data to each other, and both parties read()can read and write()write data through the and functions.

Let's take a look at the communication implemented in the way of synchronous blocking . SocketPut two cpp files in different projects and generate them separately.

server.cpp

#include <stdio.h>
#include <windows.h>

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

int main()
{
    
    
	//1. 请求协议版本
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
    
    
		printf("request failed!\n");
		return -1;
	}
	printf("request protocol success!\n");

	//2. 创建Socket
	SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (serverSocket == SOCKET_ERROR) {
    
    
		printf("create failed!\n");
		WSACleanup();
		return -2;
	}
	printf("create socket success!\n");

	//3.创建协议族
	SOCKADDR_IN addr = {
    
     0 };
	addr.sin_family = AF_INET; //协议版本
	addr.sin_addr.S_un.S_addr = inet_addr("192.168.1.127");
	addr.sin_port = htons(10086);//0-65535 10000左右

	//4.绑定
	int r = bind(serverSocket, (sockaddr*)&addr, sizeof addr);
	if (-1 == r) {
    
    
		printf("bind failed!\n");
		closesocket(serverSocket);
		WSACleanup();
		return -2;
	}
	printf("bind success!\n");

	//5.监听
	r = listen(serverSocket, 10);
	if (-1 == r) {
    
    
		printf("listen failed!\n");
		closesocket(serverSocket);
		WSACleanup();
		return -2;
	}
	printf("listen success!\n");

	//6.等待客户端连接    阻塞   
	SOCKADDR_IN cAddr = {
    
     0 };
	int len = sizeof(cAddr);
	SOCKET clientSocket = accept(serverSocket, (sockaddr*)&cAddr, &len);
	if (SOCKET_ERROR == clientSocket) {
    
    
		printf("serverd failed!\n");
		closesocket(clientSocket);
		WSACleanup();
		return -2;
	}
	printf("one client(%s) has connected server!\n", inet_ntoa(cAddr.sin_addr));

	//7.通信
	char buff[1024];
	while (1) {
    
    
		r = recv(clientSocket, buff, 1023, NULL);
		if (r > 0) {
    
    
			buff[r] = 0; // 添加'\0'
			printf(">>%s\n", buff);
		}
	}
	return 0;
}

client.cpp

#include <stdio.h>
#include <windows.h>

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

int main()
{
    
    
	//1. 请求协议版本
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
    
    
		printf("request failed!\n");
		return -1;
	}
	printf("request protocol success!\n");

	//2. 创建Socket
	SOCKET clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (clientSocket == SOCKET_ERROR) {
    
    
		printf("create failed!\n");
		WSACleanup();
		return -2;
	}
	printf("create socket success!\n");

	//3.获取服务器协议族
	SOCKADDR_IN addr = {
    
     0 };
	addr.sin_family = AF_INET; //协议版本
	addr.sin_addr.S_un.S_addr = inet_addr("192.168.1.127");
	addr.sin_port = htons(10086);//0-65535 10000左右

	//4.连接服务器
	int r = connect(clientSocket, (sockaddr*)&addr, sizeof addr);
	if (r == -1) {
    
    
		printf("connecting server failed!\n");
		return -1;
	}
	printf("connecting server success!\n");

	//5.通信
	char buff[1024];
	while (1) {
    
    
		memset(buff, 0, 1024);
		printf("please enter your words: ");
		gets_s(buff);
		r = send(clientSocket, buff, strlen(buff), NULL);
	}

	return 0;
}

Communication effect
insert image description here

insert image description here

multithreading model

The synchronous blocking method can only allow the server to serve one client. When the server does not end the network I/Oof the current client, other clients cannot connect to the server. Therefore, we can use a multi-threading model to handle requests from multiple clients.

server.cpp

#include <stdio.h>
#include <windows.h>

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

SOCKADDR_IN cAddr = {
    
     0 };
int len = sizeof(cAddr);
SOCKET clientSocket[1024];
int count = 0;

void communication(int idx) {
    
    
	char buff[1024];
	int r;
	while (1) {
    
    
		r = recv(clientSocket[idx], buff, 1023, NULL);
		if (r > 0) {
    
    
			buff[r] = 0;
			printf("%d:%s\n", idx, buff);
			//广播数据
			for (int i = 0; i < count; i++) {
    
    
				send(clientSocket[i], buff, strlen(buff), NULL);
			}
		}
	}
}

int main()
{
    
    
	//1. 请求协议版本
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
    
    
		printf("request failed!\n");
		return -1;
	}
	printf("request protocol success!\n");

	//2. 创建Socket
	SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (serverSocket == SOCKET_ERROR) {
    
    
		printf("create failed!\n");
		WSACleanup();
		return -2;
	}
	printf("create socket success!\n");

	//3.创建协议族
	SOCKADDR_IN addr = {
    
     0 };
	addr.sin_family = AF_INET; //协议版本
	addr.sin_addr.S_un.S_addr = inet_addr("192.168.1.127");
	addr.sin_port = htons(10086);//0-65535 10000左右

	//4.绑定
	int r = bind(serverSocket, (sockaddr*)&addr, sizeof addr);
	if (-1 == r) {
    
    
		printf("bind failed!\n");
		closesocket(serverSocket);
		WSACleanup();
		return -2;
	}
	printf("bind success!\n");

	//5.监听
	r = listen(serverSocket, 10);
	if (-1 == r) {
    
    
		printf("listen failed!\n");
		closesocket(serverSocket);
		WSACleanup();
		return -2;
	}
	printf("listen success!\n");

	//6.等待客户端连接    阻塞   
	while (1) {
    
    
		clientSocket[count] = accept(serverSocket, (sockaddr*)&cAddr, &len);
		if (SOCKET_ERROR == clientSocket[count]) {
    
    
			printf("serverd failed!\n");
			closesocket(serverSocket);
			WSACleanup();
			return -2;
		}
		printf("one client(%s) has connected server!\n", inet_ntoa(cAddr.sin_addr));

		CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)communication, (char*)count, NULL, NULL);
		count++;
	}

	//7.通信
	char buff[1024];
	while (1) {
    
    
		r = recv(clientSocket[count], buff, 1023, NULL);
		if (r > 0) {
    
    
			buff[r] = 0; // 添加'\0'
			printf(">>%s\n", buff);
		}
	}
	return 0;
}

client.cpp

#include <stdio.h>

#include <graphics.h> //easyX

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

SOCKET clientSocket;
HWND hWnd;

int count = 0;

void received() {
    
    
	char recvBuff[1024];
	int r;
	while (1) {
    
    
		r = recv(clientSocket, recvBuff, 1023, NULL);
		if (r > 0) {
    
    
			recvBuff[r] = 0;
			outtextxy(0, count * 20, recvBuff);
			count++;
		}
	}
}

int main()
{
    
    
	initgraph(300, 400, SHOWCONSOLE);

	//1. 请求协议版本
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
    
    
		printf("request failed!\n");
		return -1;
	}
	printf("request protocol success!\n");

	//2. 创建Socket
	clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (clientSocket == SOCKET_ERROR) {
    
    
		printf("create failed!\n");
		WSACleanup();
		return -2;
	}
	printf("create socket success!\n");

	//3.获取服务器协议族
	SOCKADDR_IN addr = {
    
     0 };
	addr.sin_family = AF_INET; //协议版本
	addr.sin_addr.S_un.S_addr = inet_addr("192.168.1.127");
	addr.sin_port = htons(10086);//0-65535 10000左右

	//4.连接服务器
	int r = connect(clientSocket, (sockaddr*)&addr, sizeof addr);
	if (r == -1) {
    
    
		printf("connecting server failed!\n");
		return -1;
	}
	printf("connecting server success!\n");

	//5.通信
	char buff[1024];
	CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)received, NULL, NULL, NULL);
	while (1) {
    
    
		memset(buff, 0, 1024);
		printf("please enter your words: ");
		gets_s(buff);
		r = send(clientSocket, buff, strlen(buff), NULL);
	}

	return 0;
}

insert image description here
insert image description here
insert image description here

references

  1. Windows network programming, socket development
  2. I/O multiplexing

Guess you like

Origin blog.csdn.net/Star_ID/article/details/126611536