TCP Socket编程(非阻塞模式)(C++)

代码来源:《Windows网络编程》(罗莉琴,詹祖桥 主编)(如造成任何不便,请联系我删除)

服务器:

// TcpServer.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <winsock2.h>
#include <iostream>

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

#define BUF_SIZE 64

int _tmain(int argc, _TCHAR* argv[])
{
	WSADATA wsd;
	SOCKET sServer;
	SOCKET sClient;
	int retVal;
	char buf[BUF_SIZE];

	//初始化Socket
	if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
	{
		printf("WSAStartup failed!\n");
		return -1;
	}
	//创建用于监听的Socket
	sServer = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	if (INVALID_SOCKET == sServer)
	{
		printf("socket failed!\n");
		WSACleanup();
		return -1;
	}
	//设置Socket为非阻塞模式
	int iMode = 1;
	retVal = ioctlsocket(sServer,FIONBIO,(u_long FAR*)&iMode);
	if (retVal == SOCKET_ERROR)
	{
		printf("ioctlsocket failed!\n");
		WSACleanup();
		return -1;
	}
	//设置服务器Socket地址
	sockaddr_in addrServ;
	addrServ.sin_family = AF_INET;
	addrServ.sin_port = htons(9990);
	addrServ.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	//绑定Socket Server到本地地址
	retVal = bind(sServer,(const struct sockaddr*)&addrServ,sizeof(sockaddr_in));
	if (retVal == SOCKET_ERROR)
	{
		printf("bind failed!\n");
		closesocket(sServer);
		WSACleanup();
		return -1;
	}
	//监听
	retVal = listen(sServer,1);
	if (retVal == SOCKET_ERROR)
	{
		printf("listen failed!\n");
		closesocket(sServer);
		WSACleanup();
		return -1;
	}
	//接受客户请求
	printf("TCP Server start...\n");
	sockaddr_in addrClient;
	int addrClientlen = sizeof(addrClient);
	//循环等待
	while (true)
	{
		sClient = accept(sServer,(sockaddr FAR*)&addrClient,&addrClientlen);
		if (INVALID_SOCKET == sClient)
		{
			int err = WSAGetLastError();
			if (err == WSAEWOULDBLOCK)
			{
				Sleep(100);
				continue;
			}
			else
			{
				printf("accept failed!\n");
				closesocket(sServer);
				WSACleanup();
				return -1;
			}		
		}
		break;

	}
	//循环接受客户端的数据,直到客户端发送quit命令后退出
	while (true)
	{
		ZeroMemory(buf,BUF_SIZE);
		retVal = recv(sClient,buf,BUFSIZ,0);
		if (SOCKET_ERROR == retVal)
		{
			int err = WSAGetLastError();
			if (err == WSAEWOULDBLOCK)
			{
				Sleep(100);
				continue;
			}
			else if (err == WSAETIMEDOUT || err == WSAENETDOWN)
			{
				printf("recv failed!\n");
				closesocket(sServer);
				closesocket(sClient);
				WSACleanup();
				return -1;
			}
		}
		//获取系统时间
		SYSTEMTIME st;
		GetLocalTime(&st);
		char sDateTime[30];
		sprintf_s(sDateTime, "%4d-%2d-%2d %2d:%2d:%2d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
		//打印输出信息
		printf("%s,Recv From Client [%s:%d]:%s\n",sDateTime,inet_ntoa(addrClient.sin_addr),addrClient.sin_port,buf);
		//如果客户端发送“quit”字符串,则服务器退出
		if (strcmp(buf, "quit") == 0)
		{
			retVal = send(sClient,"quit",strlen("quit"),0);
			break;
		}
		else
		{
			char msg[BUF_SIZE];
			sprintf_s(msg,"Message received - %s",buf);
			while (true)
			{
				retVal = send(sClient,msg,strlen(msg),0);
				if (SOCKET_ERROR == retVal)
				{
					int err = WSAGetLastError();
					if (err == WSAEWOULDBLOCK)
					{
						Sleep(100);
						continue;
					}
					else
					{
						printf("send failed!\n");
						closesocket(sServer);
						closesocket(sClient);
						WSACleanup();
						return -1;
					}
					
				}
				break;
			}
		}
	}
	
	//释放Socket
	closesocket(sServer);
	closesocket(sClient);
	WSACleanup();

	system("pause");
	return 0;
}

客户端:

// TcpClient.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <winsock2.h>
#include <string>
#include <iostream>

#pragma comment(lib,"ws2_32.lib")
#define BUF_SIZE 64


int _tmain(int argc, _TCHAR* argv[])
{
	WSADATA wsd;
	SOCKET sHost;
	SOCKADDR_IN servAddr;
	char buf[BUF_SIZE];
	int retVal;
	//初始化Socket
	if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
	{
		printf("WSAStartup failed!\n");
		return -1;
	}
	//创建Socket
	sHost = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (INVALID_SOCKET == sHost)
	{
		printf("socket failed!\n");
		WSACleanup();
		return -1;
	}
	//设置Socket为非阻塞模式
	int iMode = 1;
	retVal = ioctlsocket(sHost, FIONBIO, (u_long FAR*)&iMode);
	if (retVal == SOCKET_ERROR)
	{
		printf("ioctlsocket failed!\n");
		WSACleanup();
		return -1;
	}
	//设置服务器Socket地址
	servAddr.sin_family = AF_INET;
	servAddr.sin_port = htons(9990);
	servAddr.sin_addr.S_un.S_addr = inet_addr("ip地址");//htonl(INADDR_ANY);
	
	int sServerAddlen = sizeof(servAddr);

	//连接到服务器
	while (true)
	{
		retVal = connect(sHost,(LPSOCKADDR)&servAddr,sizeof(servAddr));
		if (SOCKET_ERROR == retVal)
		{
			int err = WSAGetLastError();
			if (err == WSAEWOULDBLOCK || err == WSAEINVAL)
			{
				Sleep(500);
				continue;
			}
			else if (err == WSAEISCONN)
			{
				break;
			}
			else
			{
				printf("connection failed!\n");
				closesocket(sHost);
				WSACleanup();
				return -1;
			}
		}
	}

	//收发数据
	while (true)
	{
		printf("Please input a string to send:");
		std::string str;
		std::getline(std::cin,str);
		ZeroMemory(buf,BUF_SIZE);
		strcpy_s(buf,str.c_str());
		while (true)
		{
			retVal = send(sHost,buf,strlen(buf),0);
			if (SOCKET_ERROR == retVal)
			{
				int err = WSAGetLastError();
				if (err == WSAEWOULDBLOCK)
				{
					Sleep(500);
					continue;
				}
				else
				{
					printf("send failed!\n");
					closesocket(sHost);
					WSACleanup();
					return -1;
				}
			}
			break;

		}
		
		while (true)
		{
			ZeroMemory(buf,BUF_SIZE);
			retVal = recv(sHost,buf,sizeof(buf)+1,0);
			if (SOCKET_ERROR == retVal)
			{
				int err = WSAGetLastError();
				if (err == WSAEWOULDBLOCK)
				{
					Sleep(100);
					printf("waiting back msg!\n");
					continue;
				}
				else if (err == WSAETIMEDOUT || err == WSAENETDOWN)
				{
					printf("recv failed!\n");
					closesocket(sHost);
					WSACleanup();
					return -1;
				}
				break;
			}
			break;
			
		}
		printf("Recv From Server:%s\n",buf);
		if (strcmp(buf, "quit") == 0)
		{
			printf("quit!\n");
			break;
		}
	}

	closesocket(sHost);
	WSACleanup();
	system("pause");

	return 0;
}


  • 5
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
我很抱歉,作为AI语言模型,我不能编写代码,但我可以给你一些思路和指导。 在Windows系统下,可以使用Winsock API来实现面向连接的socket编程非阻塞模式可以通过设置socket的属性来实现。 具体步骤如下: 1. 初始化Winsock库 在程序运行前,需要调用WSAStartup函数来初始化Winsock库。 2. 创建socket 使用socket函数创建一个socket,指定协议族、socket类型和协议号。 3. 设置非阻塞模式 使用ioctlsocket函数设置socket非阻塞模式。 4. 连接服务器 使用connect函数连接服务器。 5. 使用select函数进行非阻塞读写 使用select函数来判断socket是否可读或可写,如果可读或可写,则使用recv或send函数进行读写操作。 6. 关闭socket 使用closesocket函数关闭socket。 以下是一个简单的伪代码示例: ```python # include <winsock2.h> # define PORT 1234 int main() { // 初始化Winsock库 WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); // 创建socket SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // 设置为非阻塞模式 u_long mode = 1; ioctlsocket(sock, FIONBIO, &mode); // 连接服务器 SOCKADDR_IN serverAddr; serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(PORT); serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); connect(sock, (SOCKADDR*)&serverAddr, sizeof(serverAddr)); // 使用select函数进行非阻塞读写 fd_set readfds, writefds; while (1) { FD_ZERO(&readfds); FD_ZERO(&writefds); FD_SET(sock, &readfds); FD_SET(sock, &writefds); int ret = select(0, &readfds, &writefds, NULL, NULL); if (ret == SOCKET_ERROR) { printf("select error\n"); break; } if (FD_ISSET(sock, &readfds)) { char buffer[1024] = {0}; int len = recv(sock, buffer, 1024, 0); if (len <= 0) { printf("connection closed\n"); break; } printf("recv: %s\n", buffer); } if (FD_ISSET(sock, &writefds)) { char* data = "hello world"; int len = send(sock, data, strlen(data), 0); if (len <= 0) { printf("connection closed\n"); break; } printf("send: %s\n", data); } } // 关闭socket closesocket(sock); // 清理Winsock库 WSACleanup(); return 0; } ``` 这是一个简单的例子,实际应用中需要根据具体需求进行修改和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值