windows socket编程入门示例2

3 篇文章 0 订阅
3 篇文章 0 订阅

// tcpSocketServer.cpp
#include <stdio.h>
#include <winsock2.h>
#include <vector>

#pragma comment(lib,"ws2_32.lib")
#define IP_ADDRESS "127.0.0.1"
#define PORT		5678

static DWORD WINAPI RecvThread(void *Param);
static DWORD WINAPI SendThread(void *Param);

void main()
{
	WORD wVersionRequested;
	WSADATA wsaData;
	int retCode;
	SOCKET socketServer;
	SOCKADDR_IN addrSrv;
	SOCKADDR_IN addrClient;
	int len = sizeof(SOCKADDR);
	SOCKET socketConnection;
	std::vector<HANDLE> threadHandleSet;
	std::vector<SOCKET> clientSocketSet;

	wVersionRequested = MAKEWORD(2, 2);
	retCode = WSAStartup(wVersionRequested, &wsaData);
	if (retCode != 0)
	{
		fprintf(stderr, "Load WSADTATA failed!\n");
		return;
	}
	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
	{
		fprintf(stderr, "WSADTATA version error!\n");
		WSACleanup();
		return;
	}

	socketServer = socket(AF_INET, SOCK_STREAM, 0);//创建套接字
	if (socketServer == INVALID_SOCKET)
	{
		fprintf(stderr, "invalid socket !\n");
		WSACleanup();
		return;
	}

	//addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	addrSrv.sin_addr.S_un.S_addr = inet_addr(IP_ADDRESS);
	addrSrv.sin_family = AF_INET;//将sin_family字段设置为AF_INET,代表WinSock使用的是IP地址族
	addrSrv.sin_port = htons(PORT);//端口号
	
	retCode = bind(socketServer, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));//绑定套接字到一个IP地址和一个端口上
	if (retCode == SOCKET_ERROR)
	{
		printf("bind error !");
		closesocket(socketServer);
		WSACleanup();
		return;
	}

	retCode = listen(socketServer, 2);//将套接字设置为监听模式等待连接请求
	if (retCode == SOCKET_ERROR)
	{
		printf("listen error !");
		closesocket(socketServer);
		WSACleanup();
		return;
	}

	printf("Tcp server is running....\n");
	while (1)
	{
		//请求到来后,接收连接请求,返回一个新的对应于此次连接的套接字
		socketConnection = accept(socketServer, (SOCKADDR*)&addrClient, &len);
		if (socketConnection == INVALID_SOCKET)
		{
			printf("accept error, continue to accept new client !");
			continue;
		}
	
		printf("接受到一个连接:%s \r\n", inet_ntoa(addrClient.sin_addr));
		clientSocketSet.push_back(socketConnection);

		//创建一个子线程调用RecvThread函数,专门用来接收消息
		HANDLE recvThreadHandle = CreateThread(NULL, 0, RecvThread, &socketConnection, 0, NULL);
		if (recvThreadHandle == NULL)
		{
			fprintf(stderr, "Create recive data thread failed!\n");
		}
		threadHandleSet.push_back(recvThreadHandle);

		HANDLE sendThreadHandle = CreateThread(NULL, 0, SendThread, &socketConnection, 0, NULL);
		if (sendThreadHandle == NULL)
		{
			fprintf(stderr, "Create recive data thread failed!\n");
		}
		threadHandleSet.push_back(sendThreadHandle);
	}


	fprintf(stderr, "main thread to wait sub thread to finish.\n");
	for (int i = 0; i < threadHandleSet.size(); i++)
	{
		if (threadHandleSet[i])
		{
			WaitForSingleObject(threadHandleSet[i], INFINITE);
			CloseHandle(threadHandleSet[i]);
			fprintf(stderr, "thread %d close()\n", i + 1);
		}
	}
		
	for (int i = 0; i < clientSocketSet.size(); i++)
	{
		closesocket(clientSocketSet[i]);
		fprintf(stderr, "socket %d close.\n", i + 1);
	}


	closesocket(socketServer);
	WSACleanup();//关闭加载的套接字库
}

static DWORD WINAPI RecvThread(void *Param){
	SOCKET socketConnection = *((SOCKET *)Param);    //设置socket
	char recvBuf[1024];
	int ret;
	while (1)
	{
		ret = recv(socketConnection, recvBuf, sizeof(recvBuf), 0);
		if (ret > 0)
		{
			recvBuf[ret] = 0x00;
			fprintf(stdout, "recivce data from client success!\n");
			printf("客户端说:%s\n", recvBuf);
		}
		else if (ret == 0 || (ret == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET))
		{
			fprintf(stderr, "Client has disconneted, recive data failed!\n");
			break;
		}
		else if (ret == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK)
		{
			fprintf(stdout, "非阻塞类型返回\n");
			break;
		}
	}

	fprintf(stderr, "接收数据子线程退出\n");
	return 0;
}

static DWORD WINAPI SendThread(void *Param)
{
	SOCKET socketConnection = *((SOCKET *)Param);  
	int retCode;
	char sendBuf[128];
	
	while (1)
	{
		memset(sendBuf, 0, sizeof(sendBuf));
		printf("输入要发送给客户端的消息:\n");
		fgets(sendBuf, sizeof(sendBuf), stdin);
		int length = strlen(sendBuf);
		if (length < 2)
		{
			printf("不能发送空消息.\n");
			continue;
		}
		retCode = send(socketConnection, sendBuf, length, 0);

		if (retCode == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET)
		{
			fprintf(stderr, "Client has disconneted, send data to client failed!\n");
			break;
		}
		else if (retCode == SOCKET_ERROR)
		{
			printf("Send data to client failed!\n");
			break;
		}
		if (retCode != SOCKET_ERROR)
		{
			printf("Send data to client finished.\n");
		}
	}

	fprintf(stderr, "发送数据子线程退出\n");
	return 0;
}

// tcpSocketClient.cpp
#include <stdio.h>
#include <winsock2.h>

#pragma comment(lib,"ws2_32.lib")
#define IP_ADDRESS "127.0.0.1"
#define PORT		5678

static DWORD WINAPI RecvThread(void *Param);

void main( )
{
	WORD wVersionRequested;
	WSADATA wsaData;
	SOCKET socketClient;
	SOCKADDR_IN addrSrv;
	char sendBuf[50];
	int retCode;

	wVersionRequested = MAKEWORD(2, 2);
	retCode = WSAStartup(wVersionRequested, &wsaData);
	if (retCode != 0)
	{
		fprintf(stderr, "Load WSADTATA failed!\n");
		return;
	}
	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2){
		fprintf(stderr, "WSADTATA version error!\n");
		WSACleanup();
		return;
	}

	socketClient = socket(AF_INET, SOCK_STREAM, 0);
	if (socketClient == INVALID_SOCKET)
	{
		fprintf(stderr, "invalid socket !\n");
		WSACleanup();
		return;
	}

	addrSrv.sin_addr.S_un.S_addr = inet_addr(IP_ADDRESS);//IP地址
	addrSrv.sin_family = AF_INET;	//将sin_family字段设置为AF_INET,代表WinSock使用的是IP地址族
	addrSrv.sin_port = htons(PORT);	//端口号

	//向服务器端发出连接请求
	retCode = connect(socketClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
	if (retCode == SOCKET_ERROR)
	{
		fprintf(stderr, "Connet server error!%d\n", GetLastError());
		closesocket(socketClient);
		WSACleanup();
		return;
	}

	//创建子线程调用RecvThread函数,专门用来接收服务器端发过来的消息
	HANDLE recvDataThreadHandle =  CreateThread(NULL, 0, RecvThread, &socketClient, 0, NULL);
	if (recvDataThreadHandle == NULL)
		fprintf(stderr, "Create recive data thread failed!\n");

	//发送消息在主线程当中实现
	while (1)
	{
		memset(sendBuf, 0, sizeof(sendBuf));
		printf("请输入要发给服务器端的消息:\n");
		fgets(sendBuf, sizeof(sendBuf), stdin);
		int length = strlen(sendBuf);
		if (length < 2)
		{
			printf("不能发送空消息.\n");
			continue;
		}

		retCode = send(socketClient, sendBuf, strlen(sendBuf) + 1, 0);//发送消息
		if (retCode == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET)
		{
			fprintf(stderr, "Server has disconneted, send data to server failed!\n");
			break;
		}
		else if (retCode == SOCKET_ERROR)
		{
			printf("Send data to server failed!\n");
			break;
		}
		if (retCode != SOCKET_ERROR)
		{
			printf("Send data to server finished.\n");
		}
	}

	if (recvDataThreadHandle)
	{
		/// 同步子线程,再关闭
		WaitForSingleObject(recvDataThreadHandle, INFINITE);
		CloseHandle(recvDataThreadHandle);
	}
		
	closesocket(socketClient);
	WSACleanup();//关闭加载的套接字库
}

static DWORD WINAPI RecvThread(void *Param)
{
	SOCKET socketConnection = *((SOCKET *)Param);
	char recvBuf[1024];
	int ret;

	while (1)
	{
		ret = recv(socketConnection, recvBuf, sizeof(recvBuf), 0);
		if (ret > 0)
		{
			recvBuf[ret] = 0x00;
			fprintf(stdout, "recivce data from server success!\n");
			printf("服务器说:%s\n", recvBuf);
		}
		else if (ret == 0 || (ret == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET))
		{
			fprintf(stderr, "Server has disconneted, recive data failed!\n");
			break;
		}
		else if (ret == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK)
		{
			fprintf(stdout, "非阻塞类型返回\n");
			break;
		}
	}

	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值