C++Scoket

Windows客户端

#pragma comment(lib, "ws2_32.lib")
#include <WinSock2.h>
#include <Ws2tcpip.h>
#include <iostream>
using namespace std;

const char* DEFAULT_PORT = "5000";
const int BUF_SIZE = 1024;
const char* IP_ADDRESS = "127.0.0.1";//本机

class Client
{
private:
	SOCKET SockClient;

public:
	int client_start();
	void client_close();
	void client_func();
};

int Client::client_start()
{
	//WSADATA变量,包含windows socket执行的信息
	WSADATA WsaData;
	SockClient = INVALID_SOCKET;
	addrinfo* result = nullptr, hints;
	int ConnectResult = 0; //接收返回值
	//初始化winsock动态库(ws2_32.dll),MAKEWORD(2, 2)用于请求使用winsock2.2版本
	if (WSAStartup(MAKEWORD(2, 2), &WsaData) != 0)
		return -1;
	//其作用是用0来填充一块内存区域
	SecureZeroMemory(&hints, sizeof(hints));
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;
	//getaddrinfo函数能够处理名字到地址以及服务到端口这两种转换,
	//返回的是一个sockaddr结构的链表而不是一个地址清单。
	//这些sockaddr结构随后可由套接口函数直接使用
	ConnectResult = getaddrinfo(IP_ADDRESS, DEFAULT_PORT, &hints, &result);
	if (ConnectResult != 0)
	{
		WSACleanup();
		return -1;
	}
	//创建套接字
	SockClient = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
	if (SockClient == INVALID_SOCKET)
	{
		WSACleanup();
		return -1;
	}
	//连接服务器
	ConnectResult = connect(SockClient, result->ai_addr, result->ai_addrlen);
	if (ConnectResult == SOCKET_ERROR)
	{
		WSACleanup();
		return -1;
	}
	//释放由getaddrinfo返回的存储空间,包括addrinfo结构、ai_addr结构和ai_canonname字符串
	freeaddrinfo(result);
	return 0;
}

void Client::client_close()
{
	if (shutdown(SockClient, SD_SEND) == SOCKET_ERROR)
	{
		closesocket(SockClient);
		WSACleanup();
	}
}

void Client::client_func()
{
	char SendBuffer[BUF_SIZE];
	memset(SendBuffer, 0, BUF_SIZE);
	//发
	cin >> SendBuffer;
	int SendResult = send(SockClient, SendBuffer, BUF_SIZE, 0);
	if (SendResult < 1)
		return ;
	//收
	SendResult = recv(SockClient, SendBuffer, static_cast<int>(strlen(SendBuffer)), 0);
	if (SendResult < 1)
		return ;
	cout << SendBuffer << endl;
}
int main()
{
	Client MyClient;
	cout << MyClient.client_start() << endl;
	MyClient.client_func();
	MyClient.client_close();
	return 0;
}

Windows服务器端

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

const int IP_BUF_SIZE = 129;
const int SERVER_PORT = 5000;
const int BUF_SIZE = 1024;  //发送信息最大长度
void server_func(SOCKET SockClient);

class Server
{
public:
	Server();
	~Server();
	void wait_for_client();
private:
	//socket版本
	WORD WinsockVer;
	//存储被WSAStartup函数调用后返回的Windows Sockets数据
	WSADATA WsaData;
	//服务端socket
	SOCKET SockServer;
	//存放了服务端地址族、端口、ip地址,用来处理通信地址
	SOCKADDR_IN AddrServer;

	int AddrLen;
};

int main()
{
	Server MyServer;
	MyServer.wait_for_client();
	return 0;
}

//初始化服务器
Server::Server()
{
	//指定socket版本2.2
	WinsockVer = MAKEWORD(2, 2);
	AddrLen = sizeof(SOCKADDR_IN);
	//ip地址族
	AddrServer.sin_family = AF_INET;
	//转换网络编码,侦听本地SERVER_PORT端口
	AddrServer.sin_port = ::htons(SERVER_PORT);
	//接收任意地址的连接
	AddrServer.sin_addr.S_un.S_addr = ADDR_ANY;

	//WSAStartup的启动命令。0表示成功
	//WSA(Windows Sockets Asynchronous,Windows异步套接字)
	if (::WSAStartup(WinsockVer, &WsaData) != 0)
	{
		cerr << "WSA启动失败,错误代码: " << ::WSAGetLastError() << endl;
		system("pause");
		exit(1);
	}

	//创建socket  socket如果调用成功就返回新创建的套接字的描述符
	SockServer = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (SockServer == INVALID_SOCKET)
	{
		cerr << "创建服务器Socket失败!错误代码: " << ::WSAGetLastError() << endl;
		::WSACleanup();
		system("pause");
		exit(1);
	}

	//bind  绑定要通信的程序,成为服务器,如果函数执行成功,返回值为0,否则为SOCKET_ERROR。
	//sock_svr就是第二步成功买回的,不,是申请到的接口
	//(SOCKADDR*)&addr_svr 是指进程具体地址,就像具体电话号码一样,他的类型是一个结构体
	//addr_len就是位置的长度
	int RetVal = ::bind(SockServer, (SOCKADDR*)&AddrServer, AddrLen);
	if (RetVal != 0)
	{
		cerr << "服务器Socket绑定失败!错误代码: " << ::WSAGetLastError() << endl;
		::WSACleanup();
		system("pause");
		exit(1);
	}
	//监听端口
	RetVal = ::listen(SockServer, SOMAXCONN);
	if (RetVal == SOCKET_ERROR)
	{
		cerr << "服务器Socket监听失败!错误代码: " << ::WSAGetLastError() << endl;
		::WSACleanup();
		system("pause");
		exit(1);
	}
	cout << "服务器成功启动..." << endl;
}

Server::~Server()
{
	::closesocket(SockServer);
	::WSACleanup();
	cout << "Socket关闭..." << endl;
}

//等待客户端
void Server::wait_for_client()
{
	while (1)
	{
		//接受客户端的信息
		SOCKET SockClient;
		SOCKADDR_IN AddrClient;
		SockClient = ::accept(SockServer, (SOCKADDR*)&AddrClient, &AddrLen);
		cout << "新的连接" << endl;
		if (SockClient != INVALID_SOCKET)
		{
			thread* Thread = new thread(server_func, SockClient);
			Thread->detach();
		}
	}
}

void server_func(SOCKET SockClient)
{
	char RecvBuffer[BUF_SIZE];
	memset(RecvBuffer, 0, BUF_SIZE);
	
	//接收客户端信息
	int RecvResult = recv(SockClient, RecvBuffer, BUF_SIZE, 0);
	if (RecvResult < 1)
		return;

	//给客户端发消息
	RecvResult = send(SockClient, RecvBuffer, BUF_SIZE, 0);
	if (RecvResult < 1)
		return;
	::closesocket(SockClient);
}
};

Linux服务器端

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <iostream>
#include <thread>
#include <string.h>

const int QUEUE = 20;  //连接请求队列
const int PORT = 5000;//服务器开放端口
const int BUFFERSIZE = 1024;//Socket通信收发信息缓存区大小

//服务器TCP    Socket步骤
//1.创建socket  socket()
//2.设置socket  setsockopt()
//3.绑定IP地址端口信息  bind()
//4.开启监听  listen()
//5.接受客户端连接   accept()
//6.收发数据  send()/recv()
//7.关闭网络连接
//8.关闭监听

class Server
{
public:
	Server();
	~Server();
	void wait_for_client();
	void data_trans(int);
private:
	//存放了服务端地址族、端口、ip地址,用来处理通信地址
	sockaddr_in ServerAddr;
	//存放了客户端地址族、端口、ip地址,用来处理通信地址
	sockaddr_in ClientAddr;
	socklen_t AddrLen;
	//服务器端socket套接字描述符
	int ServerSocket;
};

int main()
{
	Server Server;
	Server.wait_for_client();
	return 0;
}

Server::Server()
{
	AddrLen = sizeof(ClientAddr);
	//若成功则返回一个sockfd (套接字描述符)
	ServerSocket = socket(AF_INET, SOCK_STREAM, 0);
	//下面设置sockaddr_in 结构体中相关参数
	ServerAddr.sin_family = AF_INET;
	//将一个无符号短整型数值转换为网络字节序,即大端模式
	ServerAddr.sin_port = htons(PORT);
	//INADDR_ANY就是指定地址为0.0.0.0的地址
	//这个地址事实上表示不确定地址,或"所有地址"、“任意地址”。
	ServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);
	//绑定IP地址端口信息
	bind(ServerSocket, (struct sockaddr*) & ServerAddr, sizeof(ServerAddr));
	//监听Socket端口
	listen(ServerSocket, QUEUE);
	std::cout << "服务器启动成功" << std::endl;
}
Server::~Server()
{
	//关闭socket套接字描述符
	close(ServerSocket);     
}
//服务器循环执行,等待客户端连接
void Server::wait_for_client()
{
	while (1)
	{
		//成功返回非负描述字,出错返回-1
		//如果accept成功,那么其返回值是由内核自动生成的一个全新描述符,代表与所返回客户的TCP连接
		int Descriptor = accept(ServerSocket, (struct sockaddr*) & ClientAddr, &AddrLen);
		if (Descriptor != -1)
		{
			//创建线程
			//如果线程调用的是某个类A的函数b(int),构造时参数为(&A::b,this,int)
			std::thread * Thread = new std::thread(&Server::data_trans, this, Descriptor);
			//分离线程
			Thread->detach();
		}
	}
}

//多线程数据传输,参数为int服务器端socket描述符
void Server::data_trans(int Descriptor)
{
	//缓存区	大小1024
	char Buffer[BUFFERSIZE];
	//缓存区初始化	置零
	memset(Buffer, 0, sizeof(Buffer));

	//接收数据  若无错误,返回读入字节数
	ssize_t ret_val = recv(Descriptor, Buffer, sizeof(Buffer), 0);
	if (ret_val != -1)
	{
		std::cout << Buffer << std::endl;
		close(Descriptor);
		return;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值