C++ 实现简单Tcp服务器端 -- Select方式

test_server.h

#ifndef INCLUDE_TEST_SERVER_H
#define INCLUDE_TEST_SERVER_H

#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <vector>

#include <winsock2.h>
#include <Ws2tcpip.h>
#pragma comment (lib, "ws2_32.lib") 

#include <fstream>
#include <iostream>
#include <time.h>

using namespace std;

#define SIZE 60
#define FILENAME "setting.txt"
#define OUTPUTFILENAME "output.txt"

class testServer
{
public:
	testServer(void);
	~testServer(void);

	bool loadSocketLib(void);
	bool readSocketParam(std::string fileName);
	bool listenClient(void);
	bool selectSocket(void);
	bool disconnectListen(void);
	bool receiveData(void);
	bool outputDataProcessing(void);
	bool writeFile(std::string outPutFileName);


protected:
	SOCKET  s_socket_fd;
	SOCKET new_socket_fd;
	std::string ipAddr;
	uint16_t portNum;
	char r_buf[SIZE];
	std::string oustr;
	fd_set readSet, tmpSet; 

};

#endif /*INCLUDE_TEST_SERVER_H*/

test_server.cpp

#include "test_server.h"

using namespace std;

/*
 *  @brief Contructor
 */
testServer::testServer(void)
{
	s_socket_fd = INVALID_SOCKET;
	new_socket_fd = INVALID_SOCKET;
	ipAddr = "";
	portNum = 0;
	memset(r_buf, 0, (size_t)SIZE);
	oustr = "";
	FD_ZERO(&tmpSet);
	FD_ZERO(&readSet);
}

/*
 *  @brief Destructor
 */
testServer::~testServer(void) {}

/*
 *  @brief Start SOCKET library
 *  @return[in] result (ture:success  false:failure)
 */
bool testServer::loadSocketLib(void)
{
	WSADATA wsaData;
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) 
	{
		cout << "startSOCKETlib error : error = start Socket lib failure" << endl;
		return false;
	}
	return true;
}

/*
 *  @brief read setting file(load socket param)
 *  @param [in] FileName
 *  @return[in] result (ture:success  false:failure)
 */
bool testServer::readSocketParam(std::string FileName)
{
	ifstream input(FileName.c_str());
	std::string line;
	std::vector<string> IPinfo;

	if (!input)
	{
		ipAddr = "";
		portNum = 0;
		cout << "load file error : error = no such file" << endl;
		return false;
	}
	else
	{
		input.seekg(std::ios::beg);
		while (getline(input, line))
		{
			IPinfo.push_back(line);
		}
		
		if (IPinfo[0].empty()|| IPinfo[1].empty())
		{
			cout << "read parameter error : error =  Parameter setting error" << endl;
			return false;
		}
		
		ipAddr = IPinfo[0];
		portNum = static_cast<uint16_t>(std::stol(IPinfo[1]));
		if (portNum > 1023 && portNum < 65536)
		{
			cout << "[load IPaddrs]:" << ipAddr << endl;
			cout << "[load portNum]:" << portNum << endl;
			return true;
		}
		else
		{
			cout << "read parameter error : error = invalid port number" << endl;
			return false;
		}

	}
}

/*
 *  @brief Listen for client requests
 *  @return [in] result (ture:success  false:failure)
 */
bool testServer::listenClient(void)
{
	if ((s_socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
	{
		cout << "create socket error,error = create socket  failed" << endl;
		return false;
	}

	sockaddr_in  sAddr;
	memset(&sAddr, 0, sizeof(sAddr));
	sAddr.sin_family = AF_INET;
	sAddr.sin_addr.s_addr = inet_addr(ipAddr.c_str());
	sAddr.sin_port = htons(portNum);

	if (bind(s_socket_fd, (struct sockaddr *)&sAddr, sizeof(sAddr)) == SOCKET_ERROR)
	{
		cout << "bind socket error,errno= bind socket failed" << endl;
		return false;
	}

	if (listen(s_socket_fd, 2) == SOCKET_ERROR)
	{
		cout << "listen socket error,errno = listen socket failed"<< endl;
		return false;
	}
	else
		cout << "======= start listen =======" << endl;
	
	FD_ZERO(&readSet); 
	FD_SET(s_socket_fd, &readSet); 
	cout << "start listening..." << endl;
	return true;
}

/*
 *  @brief disconnect listen
 *  @return [in] result (ture:success  false:failure)
 */
bool testServer::disconnectListen(void)
{
	if (closesocket(new_socket_fd) != INVALID_SOCKET)
	{
		new_socket_fd = INVALID_SOCKET;
	}

	if (closesocket(s_socket_fd) != INVALID_SOCKET)
	{
		s_socket_fd = INVALID_SOCKET;
		cout << "Listen disconnected" << endl;
		return true;
	}
	else
	{
		cout << "disconnect Listen error,errno = close socket failed" << endl;
		return false;
	}
}

/*
 *  @brief select Socket
 *  @return [in] result (ture:success  false:failure)
 */
bool testServer::selectSocket(void)
{
	FD_ZERO(&tmpSet);
	tmpSet = readSet;
	int fdnum;

	if ((fdnum = select(0, &tmpSet, NULL, NULL, NULL)) == SOCKET_ERROR)
	{
		return false;
	}
	else
		return true;
}

/*
 *  @brief
 *  @return [in] result (ture:success  false:failure)
 */
bool testServer::receiveData(void)
{
	sockaddr_in cAddr;
	socklen_t clen = sizeof(cAddr);
	memset(r_buf, 0, (size_t)SIZE);

	for (unsigned int i = 0; i < readSet.fd_count; i++)
	{
		if (FD_ISSET(readSet.fd_array[i], &tmpSet))
		{
			if (readSet.fd_array[i] == s_socket_fd) 
			{
				if ((new_socket_fd = accept(s_socket_fd, (SOCKADDR*)&cAddr, &clen)) == INVALID_SOCKET)
				{
					cout << "accept error,errno = accept failed" << endl;
					return false;
				}
				
				cout << "client[" << new_socket_fd <<  "]was listened" << endl;
				FD_SET(new_socket_fd, &readSet);
			}
			else 
			{
				int recvNum = recv(readSet.fd_array[i], r_buf, (size_t)SIZE, 0);
				if (recvNum == SOCKET_ERROR )
				{
					cout << "recv error,errno = recv data failed" << endl;
					FD_CLR(readSet.fd_array[i], &tmpSet);
					closesocket(tmpSet.fd_array[i]);
					return false;
				}
				else if (recvNum == 0)
				{
					cout << "client[" << tmpSet.fd_array[i] << "]was closed" << endl;
					FD_CLR(readSet.fd_array[i], &tmpSet);
					closesocket(tmpSet.fd_array[i]);
					return false;
				}
				else
					cout << "---------------------------------------" << endl;
					cout << "received data : <" << r_buf << ">" << endl;
					
			}
		}
	}
	return true;
}

/*
 *  @brief processing the data to be sent
 *  @return [in] result (ture:success  false:failure)
 */
bool testServer::outputDataProcessing(void)
{
	std::string times, hostName, recvData;

	// get timestamp
	time_t timep;
	time(&timep);
	char timestamp[64];
	strftime(timestamp, sizeof(timestamp), "%Y/%m/%d %H:%M:%S", localtime(&timep));
	times = timestamp;
	if (times == "")
	{
		cout << "data processing error:[time] is empty" << endl;
		return false;
	}

	// get host name
	char name[64];
	gethostname(name, sizeof(name));
	hostName = name;
	if (hostName == "")
	{
		cout << "data processing error:[hostName] is empty" << endl;
		return false;
	}

	// get recv data
	recvData = r_buf;
	if (recvData == "")
	{
		cout << "data processing error:[recvData] is empty" << endl;
		return false;
	}

	oustr = "<" + times + ">,<" + hostName + ">,<" + recvData + ">";
	cout << "data processing successed !" << endl;
	return true;
}

/*
 *  @brief write data to file
 *  @param  [in] outPutFileName
 *  @return [in] result (ture:success  false:failure)
 */
bool testServer::writeFile(std::string outPutFileName)
{

	ofstream OutFile;
	OutFile.open(outPutFileName.c_str(), ios::app);

	if (OutFile.is_open())
	{
		OutFile << oustr << endl;
		OutFile.close();
		cout << "Data has been written to :" << outPutFileName << endl;
		return true;
	}
	else
	{
		cout << "load file error : error = no such file" << endl;
		return false;
	}
}


///***********************  main  **************************/
int main()
{
	testServer tcpServer;

	if (tcpServer.loadSocketLib())
	{
		if (tcpServer.readSocketParam(FILENAME))
		{
			if (tcpServer.listenClient())
			{
				while (1)
				{
					if (tcpServer.selectSocket())
					{
						if (tcpServer.receiveData())
						{
							if (tcpServer.outputDataProcessing())
							{
								tcpServer.writeFile(OUTPUTFILENAME);
							}
							else
								continue;
						}
						else
							continue;
					}
					else
						break;
				}
				
			}
			else
				cout << " run [func: listenClient] fail" << endl;
		}
		else
			cout << " run [func: readSocketParam] fail" << endl;
	}
	else
		cout << " run [func: loadSocketLib] fail" << endl;

	tcpServer.disconnectListen();
	WSACleanup();
	system("pause");

	return 0;
}

test_client.h

#ifndef INCLUDE_TEST_CLIENT_H
#define INCLUDE_TEST_CLIENT_H

#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <vector>

#include <winsock2.h>
#include <Ws2tcpip.h>
#pragma comment (lib, "ws2_32.lib")  

#include <fstream>
#include <iostream>

using namespace std;

#define SIZE 60
#define FILENAME "setting.txt"
#define EXIT "exit"


class testClient
{
public:
	testClient(void);
	~testClient(void);

	bool loadSocketLib(void);
	bool readSocketParam(std::string FileName);
	bool connectServer(void);
	bool disconnect(void);
	bool isConnected(void);
	bool inputData(void);
	bool wantExit(void);
	bool sendData(void);


protected:
	SOCKET c_socket_fd;
	std::string ipAddr;
	uint16_t portNum;
	std::string s_data;
};

#endif /*INCLUDE_TEST_CLIENT_H*/

test_client.cpp

#include "test_client.h"

/*
 *  @brief Contructor
 */
testClient::testClient(void)
{
	c_socket_fd = INVALID_SOCKET;
	ipAddr = "";
	portNum = 0;
	s_data = "";
}

/*
 *  @brief Destructor
 */
testClient::~testClient(void) {}

/*
 *  @brief Start SOCKET library
 *  @return[in] result (ture:success  false:failure)
 */
bool testClient::loadSocketLib(void)
{
	WSADATA wsaData;
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
	{
		cout << "loadSocketLib error : error = start Socket lib failure" << endl;
		return false;
	}
	return true;
}

/*
 *  @brief read setting file(load socket param)
 *  @param [in] FileName
 *  @return[in] result (ture:success  false:failure)
 */
bool testClient::readSocketParam(std::string FileName)
{
	ifstream input(FileName.c_str());
	std::string line;
	std::vector<string> IPinfo;

	if (!input)
	{
		ipAddr = "";
		portNum = 0;
		cout << "load file error : error = no such file" << endl;
		return false;
	}
	else
	{
		input.seekg(std::ios::beg);		
		while (getline(input, line))
		{
			IPinfo.push_back(line);
		}

		if (IPinfo[0].empty() || IPinfo[1].empty())
		{
			cout << "read parameter error : error =  Parameter setting error" << endl;
			return false;
		}

		ipAddr = IPinfo[0];
		portNum = static_cast<uint16_t>(std::stol(IPinfo[1]));
		if (portNum > 1023 && portNum < 65536)
		{
			cout << "[load IPaddrs]:" << ipAddr << endl;
			cout << "[load portNum]:" << portNum << endl;
			return true;
		}
		else
		{
			cout << "read parameter error : error = invlid port number" << endl;
			return false;
		}

	}
}

/*
 *  @brief connect with TCP server
 *  @return [in] result (ture:success  false:failure)
 */
bool testClient::connectServer(void)
{
	if (c_socket_fd != INVALID_SOCKET)
	{
		cout << "is connected " << endl;
		return true;
	}

	if ((c_socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
	{
		cout << "socket error,errno= create socket failed"<< endl;
		return false;
	}
	cout << "create socket successed " << endl;

	sockaddr_in addr;
	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr(ipAddr.c_str());
	addr.sin_port = htons(portNum);

	if (connect(c_socket_fd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
	{
		cout << "connect error,errno = socket connect failed" << endl;
		return false;
	}
	return true;
}

/*
 *  @brief disconnect from TCP server
 *  @return [in] result (ture:success  false:failure)
 */
bool testClient::disconnect(void)
{
	if (c_socket_fd == INVALID_SOCKET)
	{
		cout << "disconnected" << endl;
		return true;
	}

	if (closesocket(c_socket_fd) != INVALID_SOCKET)
	{
		c_socket_fd = INVALID_SOCKET;
		cout << "disconnected" << endl;
		return true;
	}
	else
	{
		cout << "disconnect error,errno = close socket failed" << endl;
		return false;
	}
}

/*
 *  @brief confirm with TCP server connection
 *  @return [in] result (ture:success  false:failure)
 */
bool testClient::isConnected(void)
{
	if (c_socket_fd != INVALID_SOCKET)
	{
		return true;
	}
	else
		return false;
}

/*
 *  @brief processing input data
 *  @return [in] result (ture:success  false:failure)
 */
bool testClient::inputData(void)
{	
	unsigned int i;
	std::string s_data_buf = "";

	cout << "place input data..." << endl;
	if (getline(cin, s_data))
	{
		if (s_data.length() > SIZE)
		{
			cout << "inputData error,error = input limit exceeded" << endl;
			return false;
		}
		for (i = 0; i < s_data.length(); i++)
		{
			if (isascii(s_data[i]))
			{
				s_data_buf += s_data[i];
			}
		}
		s_data = s_data_buf;
		return true;
	}
	else
	{
		cout << "inputData error,error = Data input failed" << s_data << endl;
		return false;
	}
}

/*
 *  @brief Determine if it need to be closed
 *  @return [in] result (ture:success  false:failure)
 */
bool testClient::wantExit(void)
{
	if (s_data == EXIT)
	{
		return true;
	}
	else
		return false;
}

/*
 *  @brief send data to server
 *  @return [in] result (ture:success  false:failure)
 */
bool testClient::sendData(void)
{
	if (c_socket_fd != INVALID_SOCKET)
	{
		if (send(c_socket_fd, s_data.c_str(), s_data.length(), 0) == SOCKET_ERROR) {
			cout << "send data failed : send function error" << endl;
			c_socket_fd = INVALID_SOCKET;
			return false;
		}
		else
		{
			cout << "<" << s_data << "> has been sent successfully " << endl;
			cout << "------------------------------------------- " << endl;
			s_data = "";
			return true;
		}
	}
	else
	{
		cout << "send data failed :  c_socket_fd is invalid" << endl;
		return false;
	}

}

//***********************  main  **************************/
int main()
{
	testClient tcpclient;

	if (tcpclient.loadSocketLib())
	{
		if (tcpclient.readSocketParam(FILENAME))
		{
			while(1)
			{ 
				if (tcpclient.connectServer())
				{
					while (1)
					{
						if (tcpclient.isConnected())
						{
							if (tcpclient.inputData())
							{
								if (tcpclient.wantExit())
								{
									cout << "stop send data" << endl;
									break;
								}
								else
								{
									tcpclient.sendData();
								}
							}
							else
								continue;
						}
						else
							break;
					}
					if (tcpclient.wantExit())
					{
						break;
					}
				}
				else
				{
					tcpclient.disconnect();
					cout << "trying to connect again..." << endl;
				}
			}
		}
		else
			cout << " run [func: readSocketParam] fail" << endl;
	}
	else
		cout << " run [func: loadSocketLib] fail" << endl;

	tcpclient.disconnect();
	WSACleanup();
	system("pause");
	return 0;
}



版权声明:本文为weixin_38425390原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。