windows下的网络编程——Select模型实例,一款ECHO服务的实现代码

别的不多说了,看代码吧。

 

ECHO服务器端:

#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>


#define DEFAULT_PORT	5566
#define BUFFER_SIZE		4096
#define DEFAULT_ADDR_LEN 128
#define MAX_CLIENT (FD_SETSIZE -1)
int nPort	= DEFAULT_PORT;
char szAddr[DEFAULT_ADDR_LEN];
char szBuffer[BUFFER_SIZE];
BOOL bInterface = FALSE;
BOOL bEchoBack	= FALSE;

void usage(void);
void checkArgv(int argc, char **argv);
BOOL insertSocket(SOCKET *pClient, SOCKET s);

int main(int argc, char *argv[])
{
	WSAData wsaData;
	WORD wVersion = MAKEWORD(2,2);
	SOCKET s, sClient;
	SOCKADDR_IN sa, saRemote;
	int nRet, nLen, i, nLeft, idx, nRecvLen;
	SOCKET arrClientSocket[MAX_CLIENT] = {INVALID_SOCKET};

	checkArgv(argc, argv);
	nRet = WSAStartup(wVersion, &wsaData);

	if (SOCKET_ERROR == nRet)
	{
		printf("/nWindows socket startup error:%d/n", WSAGetLastError());
		return 1;
	}

	printf("Socket initalization...../n");
	
	s = socket(AF_INET, SOCK_STREAM, 0);
	if (INVALID_SOCKET == s)
	{
		printf("/nScoket was created error:%d/n", WSAGetLastError());
		return 1;
	}

	printf("socket was created/n");

	nLen = sizeof(SOCKADDR_IN);
	memset(&sa, 0, nLen);
	sa.sin_family = AF_INET;
	sa.sin_port	  = htons(nPort);

	if (bInterface)
	{
		sa.sin_addr.s_addr = inet_addr(szAddr);
	}
	else
	{
		sa.sin_addr.s_addr = htonl(INADDR_ANY);
	}

	nRet = bind(s, (LPSOCKADDR)&sa, nLen);
	if (SOCKET_ERROR == nRet)
	{
		printf("Socket bind error:%d/n", WSAGetLastError());
		return 1;
	}

	printf("bind was successed/n");

	nRet = listen(s, 8);
	if (SOCKET_ERROR == nRet)
	{
		printf("Socket listen error:%d/n", WSAGetLastError());
		return 1;
	}
	
	printf("listen was successed/n");

	fd_set fdRead;
	for(i = 0;i < MAX_CLIENT; i++)
	{
		arrClientSocket[i] = INVALID_SOCKET;
	}

	for(;;)
	{
		//初始化队列,将所有套接字加入。
		FD_ZERO(&fdRead);
		FD_SET(s, &fdRead);
		for(i = 0; i < MAX_CLIENT; i++)
		{
			if (INVALID_SOCKET != arrClientSocket[i])
			{
				FD_SET(arrClientSocket[i], &fdRead);
			}
		}

		nRet = select(0, &fdRead, NULL, NULL, NULL);
		if (SOCKET_ERROR == nRet)
		{
			printf("/nSelect() error:%d/n", WSAGetLastError());
			break;
		}

		if (nRet > 0)
		{
			//说明有新SOCKET连接到服务器
			if(FD_ISSET(s, &fdRead))
			{
				sClient = accept(s, (LPSOCKADDR)&saRemote, &nLen);
				insertSocket(arrClientSocket, sClient);
				printf("Sokcet:%d, was accept()/n", sClient);
				continue;
			}
			for(i = 0; i < MAX_CLIENT; i++)
			{
				if (FD_ISSET(arrClientSocket[i], &fdRead))
				{
					memset(szBuffer, 0, BUFFER_SIZE);
					nRet = recv(arrClientSocket[i], szBuffer, BUFFER_SIZE, 0);
					if (nRet <= 0)
					{
						closesocket(arrClientSocket[i]);
						arrClientSocket[i] = INVALID_SOCKET;
						continue;
					}

					nRecvLen = nRet;
					printf("Socket:%d, %d, send data:%s/n", arrClientSocket[i], nRet, szBuffer);
					

					if (!bEchoBack)
					{
						nRet = getpeername(arrClientSocket[i], (LPSOCKADDR)&saRemote, &nLen);
						if (SOCKET_ERROR == nRet)
						{
							printf("/ngetpeername() error:%d/n", WSAGetLastError());
							continue;
						}
						nLeft = nRecvLen;
						idx = 0;
						while (nLeft > 0)
						{
							nRet = send(arrClientSocket[i], &szBuffer[idx], nLeft, 0);
							if (0 == nRet) 
								break;
							else if (SOCKET_ERROR == nRet)
							{
								printf("Send() failed:%d/n", WSAGetLastError());
								break;
							}
							nLeft -= nRet;
							idx += nRet;
						}
					}
				}
			}
		}
	}
	closesocket(s);
	WSACleanup();
	return 0;
}

void usage(void)
{
	printf("usage: selectecho.exe [-p:5566] [-i:127.0.0.1] [-o]/n/n");
	printf("/t-p:监听的端口号, 在1024到65535之间/n");
	printf("/t-i:监听的服务器地址/n");
	printf("/t-o:是否将数据发回客户端/n/n");
	ExitProcess(1);
}

void checkArgv(int argc, char **argv)
{
	int i;
	for(i = 1; i < argc; i++)
	{
		if(('/' == argv[i][0]) || ('-' == argv[i][1]))
		{
			switch(tolower(argv[i][1]))
			{
				case 'p':
					nPort = atoi(&argv[i][3]);
					break;
				case 'i':
					memset(szAddr, 0, DEFAULT_ADDR_LEN);
					strcpy(szAddr, &argv[i][3]);
					bInterface = TRUE;
					break;
				case 'o':
					bEchoBack = TRUE;
					break;
				default:
					usage();
					break;
			}
		}
	}
}

BOOL insertSocket(SOCKET *pClient, SOCKET s)
{
	int i;
	BOOL bResult = FALSE;
	for(i = 0; i < MAX_CLIENT; i++)
	{
		if (INVALID_SOCKET == pClient[i])
		{
			pClient[i] = s;
			bResult = TRUE;
			break;
		}
	}
	return bResult;
}

测试用客户端,目前地址写在了程序中,用户可以自行修改。

 

#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>

#define SERVER_PORT	5566
#define BUFFER_SIZE 4096
#define MAX_ADDR_LEN 128

int nPort = SERVER_PORT;
char szBuffer[BUFFER_SIZE];
char szAddr[MAX_ADDR_LEN];

void usage(void);
void checkArgv(int argc, char **argv);

int main(int argc, char *argv[])
{
	int nRet, nLen, nAddrLen, i;
	SOCKET s;
	SOCKADDR_IN sa;

	WSAData wsaData;
	WORD wVersion = MAKEWORD(2,2);

	checkArgv(argc, argv);

	nRet = WSAStartup(wVersion, &wsaData);
	if (SOCKET_ERROR == nRet)
	{
		printf("Socket init error/n");
		return 1;
	}
	
	s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (INVALID_SOCKET == s)
	{
		printf("Socket was created failse:%d/n", WSAGetLastError());
		closesocket(s);
		WSACleanup();
		return 1;
	}

	nAddrLen = sizeof(SOCKADDR_IN);
	memset(&sa, 0, nAddrLen);
	sa.sin_family = AF_INET;
	sa.sin_port	  = htons(nPort);
	sa.sin_addr.s_addr = inet_addr("127.0.0.1");

	nRet = connect(s, (LPSOCKADDR)&sa, nAddrLen);
	if (SOCKET_ERROR == nRet)
	{
		printf("socket connect() failse:%d/n", WSAGetLastError());
		closesocket(s);
		WSACleanup();
		return 1;
	}

	for(;;)
	{
		printf("/nSend Message to ECHO:");
		memset(szBuffer, 0, BUFFER_SIZE);
		nRet = scanf("%s", szBuffer);
		if (BUFFER_SIZE < nRet)
		{
			szBuffer[BUFFER_SIZE-1] = '/0';
		}
		if (0 == strcmp("quit",szBuffer)) break;		//输入QUIT退出当前客户端
		nRet = send(s, szBuffer, strlen(szBuffer), 0);
		if (SOCKET_ERROR == nRet)
		{
			printf("Socket send() failse:%d/n", WSAGetLastError());
			break;
		}
		memset(szBuffer, 0, BUFFER_SIZE);
		nRet = recv(s, szBuffer, BUFFER_SIZE, 0);
		printf("Server ECHO back:%s/n", szBuffer);
	}
	

	closesocket(s);
	WSACleanup();
	return 0;
}

void usage(void)
{
	printf("usage: selectecho.exe -i:127.0.0.1 [-p:5566]/n");
	printf("/t-i:服务器地址/n");
	printf("/t-p:服务器端口号, 在1024到65535之间/n");
	ExitProcess(1);
}

void checkArgv(int argc, char **argv)
{
	int i;
	memset(szAddr, 0, MAX_ADDR_LEN);
	for(i = 1; i < argc; i++)
	{
		if(('/' == argv[i][0]) || ('-' == argv[i][1]))
		{
			switch(tolower(argv[i][1]))
			{
				case 'p':
					nPort = atoi(&argv[i][3]);
					break;
				case 'i':
					strcpy(szAddr, &argv[i][3]);
					printf("%s", argv[i][3]);
					break;
				default:
					usage();
					break;
			}
		}
	}
}

Windows下的编译命令为:

cl -o 服务器程序名称.exe 源文件名称.cpp WS2_32.lib

 

客户端编译同上,只是修改文件名即可。




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值