C++ socket TCP網絡編程

0.通信步驟流程圖(左:服務器;右:客戶端;)

1.服務器代碼

1.1 服務器類頭文件(CServer_Wins.h)

#pragma once

#include <winsock2.h>

class CServer_Wins
{
public:
	CServer_Wins();
	void RecMsg();
	void stopRec();
	~CServer_Wins();
private:
	bool m_terminal;
	SOCKET m_slisten; //創建監聽套接字
};

1.2服務器類源文件(CServer_Wins.cpp)

#define _WINSOCK_DEPRECATED_NO_WARNINGS

#include "CServer_Wins.h"
#include <iostream>
#include <string>

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

CServer_Wins::CServer_Wins():m_terminal(false)
{
	//必須進行如下初始化, 否則socket()會返回10093錯誤
	//初始化WSA  
	WORD sockVersion = MAKEWORD(2, 2);
	WSADATA wsaData;
	if (WSAStartup(sockVersion, &wsaData) != 0) //通過一個進程初始化ws2_32.dll
	{
		std::cout << "Initialize WSA failed" << std::endl;
		return ;
	}

	//創建套接字
	m_slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (m_slisten == INVALID_SOCKET)
	{
		printf("%d\n", WSAGetLastError());
		printf("%s\n", "Socket Error!");

		return ;
	}
	struct sockaddr_in sin;
	sin.sin_family = AF_INET; //設置地址家族
	sin.sin_port = htons(8888); //設置端口號,inet_addr("192.168.1.0");
	sin.sin_addr.S_un.S_addr = INADDR_ANY; //設置地址

	//綁定端口
	if ((bind(m_slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR))
		//套接字, 指向sockaddr_in結構體的指針,參數長度 
	{
		printf("%s\n", "Bind Error!");
	}
        if (listen(m_slisten, 20) == SOCKET_ERROR)  //套接字, 爲該套接字排隊的最大連接數
											   //此時, slisten 變爲監聽套接字
	{
		printf("%s\n", "Listen Error!");
		closesocket(m_slisten); //關閉監聽套接字
		WSACleanup(); //終止Ws2_32.dll的使用
		return;
	}

}
void CServer_Wins::RecMsg()
{
	std::cout << "Rec thread begin ..." << std::endl;
	struct sockaddr_in remoteAddr;     //存儲 通過accept 得到的 客戶端IP地址
	int nAddrlen = sizeof(remoteAddr); //IP地址長度
	while (!m_terminal)
	{
		//std::cout << "thread is running" << std::endl;
		
		SOCKET sClient = accept(m_slisten, (SOCKADDR*)&remoteAddr, &nAddrlen);
		if (sClient == INVALID_SOCKET)
		{
			printf("accept error !");
			continue;
		}
		char revData[1025]; //接收回來的數據
		int ret = 0; //接收回來的字節數
		//接收數據  
		ret = recv(sClient, revData, 1024, 0);
		if (ret > 0)
		{
			revData[ret] = '\0';
			std::cout << "Client " << inet_ntoa(remoteAddr.sin_addr) << " say : " << revData << std::endl;
		}

		//發送數據  
		send(sClient, "Server get msg!", strlen("Server get msg!"), 0);
		//連接套接字, 要發送數據所存儲位置對應的地址, 長度
		closesocket(sClient); //關閉連接套接字

		std::cout << "session end" << std::endl;
		Sleep(30);
	}

	std::cout << "Rec thread end..." << std::endl;
}
void CServer_Wins::stopRec()
{
	m_terminal = true;
}
CServer_Wins::~CServer_Wins()
{
	std::cout << "~CServer_Wins()" << std::endl;
	closesocket(m_slisten); //關閉監聽套接字
	WSACleanup(); //終止Ws2_32.dll的使用
}

1.3 服務器主函數

#include <iostream>
#include <thread>

#include "CServer_Wins.h"

using namespace std;

int main()
{
	CServer_Wins server;

	thread rec(&CServer_Wins::RecMsg, &server);

	rec.join();
        std::cout << "I love China!\n"; 

	return 0;
}

2.客戶端代碼

2.1客戶端類頭文件(CClient_Wins.h)

#pragma once

#include <winsock2.h>

class CClient_Wins
{
public:
	CClient_Wins();
	bool ConnectSerever(char ServerIP[]);
	void SendMsg(char ServerIP[], const char SendBuff[]);
	void RecMsg();
	void stopRecv();
	~CClient_Wins();

private:
	SOCKET m_cSocket;
	bool m_terminate;
};

2.2客戶端類源文件(CClient_Wins.cpp)


#define _WINSOCK_DEPRECATED_NO_WARNINGS

#include "CClient_Wins.h"
#include <iostream>
#include <string>

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

struct sockaddr_in sin_client;

CClient_Wins::CClient_Wins():m_terminate(false)
{
	//必須進行如下初始化, 否則socket()會返回10093錯誤
	//初始化WSA  
	WORD sockVersion = MAKEWORD(2, 2);
	WSADATA wsaData;
	if (WSAStartup(sockVersion, &wsaData) != 0) //通過一個進程初始化ws2_32.dll
	{
		std::cout << "Initialize WSA failed" << std::endl;
		return;
	}

}
bool CClient_Wins::ConnectSerever(char ServerIP[])
{
	bool ret = false;
	sin_client.sin_addr.S_un.S_addr = inet_addr(ServerIP); //設置地址
	if (connect(m_cSocket, (sockaddr*)&sin_client, sizeof(sin_client)) == 0)
	{
		ret = true;
	}

	return ret;
}
void CClient_Wins::SendMsg(char ServerIP[], const char SendBuff[])
{
	//創建套接字
	m_cSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (m_cSocket == INVALID_SOCKET)
	{
		printf("%d\n", WSAGetLastError());
		printf("%s\n", "Socket Error!");

		return;
	}

	sin_client.sin_family = AF_INET; //設置地址家族
	sin_client.sin_port = htons(8888); //設置端口號,inet_addr("192.168.1.0");
	ConnectSerever(ServerIP);
	send(m_cSocket, SendBuff, strlen(SendBuff), 0);
	
}
void CClient_Wins::RecMsg()
{
	char buffer[1025];
	int num = 0;
	while (!m_terminate)
	{
		num = recv(m_cSocket, buffer, 1024, 0);//阻塞

		if (num > 0)
		{
			buffer[num] = '\0';
			std::cout << "Server say:" << buffer << std::endl;
			closesocket(m_cSocket);
		}
	}

	closesocket(m_cSocket); //關閉監聽套接字
}
void CClient_Wins::stopRecv()
{
	m_terminate = true;
}
CClient_Wins::~CClient_Wins()
{
	closesocket(m_cSocket); //關閉監聽套接字
	WSACleanup(); //終止Ws2_32.dll的使用
}

2.3 客戶端主函數

#include <iostream>
#include <thread>
#include <string>
#include "CClient_Wins.h"

using namespace std;

int main()
{
	CClient_Wins client;

	//getchar();
	char IP[] = "127.0.0.1";
	client.ConnectSerever(IP);
	thread cli(&CClient_Wins::RecMsg, &client);
	cout << "Please input send content:" << endl;
	string content;
	cin >> content;
	while (content.compare("stop") != 0)
	{
		client.SendMsg(IP, content.c_str());
		cin >> content;
	}

	cli.join();
	std::cout << "I love China!\n"; 

	return 0;
}

3.效果圖

服務器

客戶端

 

注:

開發環境: Windows7 & Visual Studio 2017

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章