ipv4 ipv6 客户端 服务端代码

客户端:

客户端配置文件 client.ini

[IP_FAMILY]
;0-ipv4 1-机器存在ipv6协议,则使用ipv6,否则使用ipv4 2-ipv6
FAMILY=1

[MODE]
;0-普通连接 1-使用getaddrinfo函数取得地址以创建连接
METHOD=1

[IPV4]
IP=127.0.0.1
PORT=9527

[IPV6]
IP=::1
PORT=9527

 

 

客户端代码

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

#include "stdafx.h"
#include <stdio.h>
#include <tchar.h>
#include <cstring>
#include <ws2tcpip.h>
using namespace std;
#pragma comment(lib, "ws2_32.lib ")  //linking to the library


// 配置文件信息
typedef struct config_info_f
{
	int nIPFamily;		// ip协议栈 AF_UNSPEC AF_INET AF_INET6
	int nMethod;		// 方法
	int nPort;			// 端口
	char strIP[256];	// ip地址
}ST_CONFIG_INFO;
ST_CONFIG_INFO g_stClientInfo;

// 取得本机的 ipv4 与 ipv6
int GetIPV4AndIPV6()
{
	struct addrinfo *ailist;
	struct addrinfo hint;
	PHOSTENT hostinfo;
	char hostname[255] = {0}; //主机名
	memset(hostname, 0, 255);
	char *port = "80";      //端口号
	int ilRc;
	gethostname(hostname, sizeof(hostname));

	//获得本地ipv4地址 gethostbyname 指向静态数组,不需要释放
	if ((hostinfo = gethostbyname(hostname)) == NULL) 
	{
		errno = GetLastError();
		fprintf(stderr, "gethostbyname Error:%d\n", errno);
		return 1;
	}
	LPCSTR ip;
	while (*(hostinfo->h_addr_list) != NULL) //输出ipv4地址
	{
		ip = inet_ntoa(*(struct in_addr *) *hostinfo->h_addr_list);
		printf("gethostbyname ipv4 addr = %s\n", ip);
		hostinfo->h_addr_list++;
	}

	// 使用getaddrinfo 获得IPV4/IPV6
	hint.ai_family = AF_UNSPEC;        //hint 的限定设置
	hint.ai_socktype = SOCK_STREAM;   //这里可是设置 socket type    比如  SOCK_DGRAM
	hint.ai_flags = AI_PASSIVE;       // flags 的标志很多。常用的有AI_CANONNAME;
	hint.ai_protocol = 0;             //设置协议  一般为0,默认
	hint.ai_addrlen = 0;              //下面不可以设置,为0,或者为NULL
	hint.ai_canonname = NULL;
	hint.ai_addr = NULL;
	hint.ai_next = NULL;
	ilRc = getaddrinfo(hostname, port, &hint, &ailist); //通过主机名获得地址信息
	//ilRc = getaddrinfo(NULL, port, &hint, &ailist); //通过主机名获得地址信息
	if (ilRc < 0)
	{
		char str_error[100];
		strcpy_s(str_error, sizeof(str_error), (char *)gai_strerror(errno));
		printf("str_error = %s", str_error);
		return 0;
	}
	if (ailist == NULL)
	{
		printf("sorry not find the IP address,please try again \n");
	}

	char str[32] = {0};
	for (struct addrinfo* aip = ailist; aip != NULL; aip = aip->ai_next) //显示获取的信息
	{
		// ipv4
		if (aip->ai_family == AF_INET)
		{
			inet_ntop(AF_INET,
				&(((struct sockaddr_in *)(aip->ai_addr))->sin_addr),
				str, 32);
			printf("ipv4->	%s\n", str);
		}
		else// ipv6
		{
			inet_ntop(AF_INET6,
				&(((struct sockaddr_in6 *)(aip->ai_addr))->sin6_addr),
				str, 32);
			printf("ipv6->	%s\n", str);
		}
	}

	// 释放节点
	freeaddrinfo(ailist);
	return 0;
}

// 判断当前主机是否支持IPV6 0-不支持 1-支持
int ExistIPV6()
{
	int nRet = 0;
	struct addrinfo* ailist=NULL;
	struct addrinfo hint;
	hint.ai_family = AF_INET6;//hint 的限定设置
	hint.ai_socktype = SOCK_STREAM;//这里可是设置 socket type    比如  SOCK_DGRAM
	//hint.ai_flags = AI_PASSIVE;  // flags 的标志很多。常用的有AI_CANONNAME;
	hint.ai_protocol = 0;         //设置协议  一般为0,默认
	hint.ai_addrlen = 0;          //下面不可以设置,为0,或者为NULL
	hint.ai_canonname = NULL;
	hint.ai_addr = NULL;
	hint.ai_next = NULL;
	//如果节点名NULL,hint.ai_flags 不设置,则返回的地址将是回环地址的IPV6,可用于判断当前机器是否支持 ipv6
	int ilRc = getaddrinfo(NULL, "80", &hint, &ailist); 
	if ((ilRc == 0) && (ailist != NULL))
	{
		// 取得ipv6的环回地址
		for (struct addrinfo* aip = ailist; aip != NULL; aip = aip->ai_next) //显示获取的信息
		{
			struct sockaddr_in6 * sinp6 = (struct sockaddr_in6 *)aip->ai_addr;
			char temp[128];sprintf_s(temp, sizeof(temp), "%s", "Loopback Address IPV6->\t");
			for (int i = 0; i < 16; i++)
			{
				if (((i - 1) % 2) && (i > 0))
				{
					strcat_s(temp, ":");
				}
				char node[8];sprintf_s(node, sizeof(node),"%02x", sinp6->sin6_addr.u.Byte[i]);
				strcat_s(temp, node);
			}
			//printf("%s\n", temp);
		}
		nRet = 1;

		// 释放节点
		freeaddrinfo(ailist);
	}

	return nRet;
}


// 收发数据
void SendAndRecv(SOCKET sockfd)
{
	char buffer[8192]; sprintf_s(buffer, sizeof(buffer), "%s", "[client]: There are moments in life when you miss someone so much that you just want to pick them from your dreams and hug them for real! Dream what you want to dream;go where you want to go;be what you want to be,because you have only one life and one chance to do all the things you want to do.[client end]");
	int len = send(sockfd, buffer, strlen(buffer), 0);
	printf("%ld\t send->%s \t len=%d\n",GetTickCount(), buffer, len);

	memset(buffer, 0x00, sizeof(buffer));
	len = recv(sockfd, buffer, 8192, 0);
	if (len > 0)
	{
		printf("%ld\t recv<- %s \t len=%d\n", GetTickCount(), buffer, len);
	}
	else
	{
		printf("消息接收失败\n");
	}
}


// 普通方式连接服务端
void ConnectServerWithCommon(int nFamily, u_short Port, char* strAddress)
{
	SOCKET sockfd = socket(nFamily, SOCK_STREAM, IPPROTO_TCP);
	if (sockfd == INVALID_SOCKET)
	{
		printf("socket function error\n");
		return;
	}


	// 创建连接
	int nRet = 0;
	if (AF_INET6 == nFamily)
	{
		sockaddr_in6 dest;
		memset(&dest, 0, sizeof(sockaddr_in6));
		dest.sin6_port = htons(Port);
		int conret = inet_pton(AF_INET6, strAddress, &dest.sin6_addr);
		if (conret != 1)
		{
			printf("inet_pton error\n");
			return;
		}
		dest.sin6_family = AF_INET6;
		nRet = connect(sockfd, (struct sockaddr *) &dest, sizeof(sockaddr_in6));
	}
	else
	{
		SOCKADDR_IN ServerAddr;
		memset(&ServerAddr, 0, sizeof(SOCKADDR_IN));
		ServerAddr.sin_family = AF_INET;
		ServerAddr.sin_port = htons(Port);
		ServerAddr.sin_addr.s_addr = inet_addr(strAddress);
		nRet = connect(sockfd, (SOCKADDR *)&ServerAddr, sizeof(ServerAddr));
	}

	if (nRet == SOCKET_ERROR)
	{
		printf("FILE=%s\tLINE=%d\t  connect failed with error %d, ip: %s, port: %d\n", __FILE__, __LINE__, WSAGetLastError(), strAddress, Port);
		closesocket(sockfd);
		return ;
	}

	// 收发数据
	SendAndRecv(sockfd);

	closesocket(sockfd);
}



// 使用getaddrinfo函数的辅助来连接服务端
void ConnectServerWithFuncgetaddrinfo(int nFamily, u_short Port, char* strAddress)
{
	struct addrinfo *ailist;
	struct addrinfo hint;
	hint.ai_family = nFamily;        //hint 的限定设置
	hint.ai_socktype = SOCK_STREAM;   //这里可是设置 socket type    比如  SOCK_DGRAM
	hint.ai_protocol = 0;             //设置协议  一般为0,默认
	hint.ai_addrlen = 0;              //下面不可以设置,为0,或者为NULL
	hint.ai_canonname = NULL;
	hint.ai_addr = NULL;
	hint.ai_next = NULL;
	char strPort[32]; sprintf_s(strPort, sizeof(strPort), "%d", Port);
	int ilRc = getaddrinfo(strAddress, strPort, &hint, &ailist); //通过主机名获得地址信息
	if ((ilRc != 0) || (NULL == ailist))
	{
		printf("getaddrinfo error\n");
		return;
	}
	
	// 创建 socket
	SOCKET sockfd = socket(ailist->ai_family, ailist->ai_socktype, ailist->ai_protocol);
	if (sockfd == INVALID_SOCKET)
	{
		printf("socket function error\n");
		return;
	}

	// 建立连接
	int nRet = connect(sockfd, ailist->ai_addr, ailist->ai_addrlen);
	if (nRet == SOCKET_ERROR)
	{
		printf("FILE=%s\tLINE=%d\t  connect failed with error %d, ip: %s, port: %d\n", __FILE__, __LINE__, WSAGetLastError(), strAddress, Port);
		closesocket(sockfd);
		return;
	}

	// 收发数据
	SendAndRecv(sockfd);

	closesocket(sockfd);
}



// 读取配置文件
void ReadInfoFromIni()
{
	// 数据初始化
	memset(&g_stClientInfo, 0x00, sizeof(g_stClientInfo));

	// 修改文件的路径为../conf/
	char szIniName[MAX_PATH];	// 配置文件的全名称 
	memset(szIniName, 0x00, sizeof(szIniName));
	strcpy_s(szIniName, "./client.ini");


	// 协议栈
	int nFamily = GetPrivateProfileIntA("IP_FAMILY", "FAMILY", 1, szIniName);
	if (0 == nFamily)
	{
		g_stClientInfo.nIPFamily = AF_INET;
	}
	else if (2 == nFamily)
	{
		g_stClientInfo.nIPFamily = AF_INET6;
	}
	else
	{
		g_stClientInfo.nIPFamily = AF_INET;
		// 判断机器是否支持IPV6
		int nIPV6Suport = ExistIPV6();
		if (nIPV6Suport)
		{
			g_stClientInfo.nIPFamily = AF_INET6;
		}
	}

	// 创建连接的方法
	g_stClientInfo.nMethod = GetPrivateProfileIntA("MODE", "METHOD", 0, szIniName);

	// 读取IP与端口号
	if (AF_INET6 == g_stClientInfo.nIPFamily)
	{
		GetPrivateProfileStringA("IPV6", "IP", "::1", g_stClientInfo.strIP, 256, szIniName);
		g_stClientInfo.nPort = GetPrivateProfileIntA("IPV6", "PORT", 0, szIniName);
	}
	else
	{
		GetPrivateProfileStringA("IPV4", "IP", "127..0.0.1", g_stClientInfo.strIP, 256, szIniName);
		g_stClientInfo.nPort = GetPrivateProfileIntA("IPV4", "PORT", 0, szIniName);
	}
}




int _tmain(int argc, _TCHAR* argv[])
{
	//	printf("Received %d bytes from client: [%.*s]\n", 5, 5, "12345etererer");
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;
	wVersionRequested = MAKEWORD(1, 1);
	err = WSAStartup(wVersionRequested, &wsaData);//initiate the ws2_32.dll and match the version
	if (err != 0)
	{
		return 0;
	}
	//if the version is not matched ,then quit and terminate the ws3_32.dll
	//if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
	//{
	//	WSACleanup();
	//	return 0;
	//}

	// 取得本机的 ipv4 与 ipv6
	GetIPV4AndIPV6();
	
	// 读取配置文件
	ReadInfoFromIni();

	while (true)
	{
		if (g_stClientInfo.nMethod == 1)
		{
			ConnectServerWithFuncgetaddrinfo(g_stClientInfo.nIPFamily, (unsigned short)g_stClientInfo.nPort, g_stClientInfo.strIP);
		}
		else
		{
			ConnectServerWithCommon(g_stClientInfo.nIPFamily, (unsigned short)g_stClientInfo.nPort, g_stClientInfo.strIP);
		}

		Sleep(300);
	}


	WSACleanup();

	while (true)
	{
		getchar();
	}

	return 0;
}

 

 

服务端

服务端配置文件 server.ini

[IP_FAMILY]
;0-ipv4 1-机器存在ipv6协议,则使用ipv6,否则使用ipv4 2-ipv6
FAMILY=1

[MODE]
;0-普通连接 1-使用getaddrinfo函数取得地址以创建连接
METHOD=1

[SERVER]
PORT=9527

  

服务端代码

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

#include "stdafx.h"
#include <stdio.h>
#include <tchar.h>
#include <cstring>
#include <ws2tcpip.h>
using namespace std;

#pragma comment(lib, "ws2_32.lib ")  //linking to the library

// 配置文件信息
typedef struct config_info_f
{
	int nIPFamily;		// ip协议栈 AF_UNSPEC AF_INET AF_INET6
	int nMethod;		// 方法
	int nPort;			// 端口
}ST_CONFIG_INFO;
ST_CONFIG_INFO g_stServerInfo;


// 打印windows 错误信息
LPSTR DecodeError(int ErrorCode)
{
	static char Message[1024];
	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
		FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, ErrorCode,
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		(LPSTR)Message, 1024, NULL);
	return Message;
}


// 判断当前主机是否支持IPV6 0-不支持 1-支持
int ExistIPV6()
{
	int nRet = 0;
	struct addrinfo* ailist = NULL;
	struct addrinfo hint;
	hint.ai_family = AF_INET6;//hint 的限定设置
	hint.ai_socktype = SOCK_STREAM;//这里可是设置 socket type    比如  SOCK_DGRAM
	//hint.ai_flags = AI_PASSIVE;  // flags 的标志很多。常用的有AI_CANONNAME;
	hint.ai_protocol = 0;         //设置协议  一般为0,默认
	hint.ai_addrlen = 0;          //下面不可以设置,为0,或者为NULL
	hint.ai_canonname = NULL;
	hint.ai_addr = NULL;
	hint.ai_next = NULL;
	//如果节点名NULL,hint.ai_flags 不设置,则返回的地址将是回环地址的IPV6,可用于判断当前机器是否支持 ipv6
	int ilRc = getaddrinfo(NULL, "80", &hint, &ailist);
	if ((ilRc == 0) && (ailist != NULL))
	{
		// 取得ipv6的环回地址
		for (struct addrinfo* aip = ailist; aip != NULL; aip = aip->ai_next) //显示获取的信息
		{
			struct sockaddr_in6 * sinp6 = (struct sockaddr_in6 *)aip->ai_addr;
			char temp[128]; sprintf_s(temp, sizeof(temp), "%s", "Loopback Address IPV6->\t");
			for (int i = 0; i < 16; i++)
			{
				if (((i - 1) % 2) && (i > 0))
				{
					strcat_s(temp, ":");
				}
				char node[8]; sprintf_s(node, sizeof(node), "%02x", sinp6->sin6_addr.u.Byte[i]);
				strcat_s(temp, node);
			}
			//printf("%s\n", temp);
		}
		nRet = 1;

		// 释放节点
		freeaddrinfo(ailist);
	}

	return nRet;
}


// 收发数据
void SendAndRecv(SOCKET sockfd)
{
	char buffer[8192]; sprintf_s(buffer, sizeof(buffer), "%s", "[server]:You Have Only One Life [server end]");
	int len = send(sockfd, buffer, strlen(buffer), 0);
	printf("%ld\t send->%s \t len=%d\n", GetTickCount(), buffer, len);

	memset(buffer, 0x00, sizeof(buffer));
	len = recv(sockfd, buffer, 8192, 0);
	if (len > 0)
	{
		printf("%ld\t recv<- %s \t len=%d\n", GetTickCount(), buffer, len);
	}
	else
	{
		printf("消息接收失败\n");
	}
}


// 普通方式连接服务端
int CreateServerWithCommon(u_short Port, int nFamily)
{
	SOCKADDR_STORAGE From;
	int FromLen = sizeof(From);
	SOCKET ServSock;

	// 创建套接字
	ServSock = socket(nFamily, SOCK_STREAM, IPPROTO_IP);
	if (ServSock == INVALID_SOCKET)
	{
		fprintf(stderr, "socket() failed with error %d: %s\n", WSAGetLastError(), DecodeError(WSAGetLastError()));
		getchar(); return -1;
	}

	// 绑定套接字
	if (nFamily == AF_INET6) // IPV6
	{
		struct sockaddr_in6 my_addr;
		memset(&my_addr, 0x00, sizeof(my_addr));
		my_addr.sin6_family = AF_INET6;
		my_addr.sin6_port = htons(Port);
		my_addr.sin6_addr = in6addr_any;
		if (0 != bind(ServSock, (struct sockaddr*)&my_addr, sizeof(sockaddr_in6)))
		{
			printf("ipv6 Bind Failure:\n");
			fprintf(stderr, "socket() failed with error %d: %s\n", WSAGetLastError(), DecodeError(WSAGetLastError()));
			return -1;
		}
	}
	else// IPV4
	{
		// 绑定地址
		struct sockaddr_in addr;
		memset(&addr, 0x00, sizeof(addr));
		addr.sin_port = htons(Port);
		// "0.0.0.0" 标识任意连接可接入, 下面两句等价
		inet_pton(AF_INET, "0.0.0.0", &addr.sin_addr);
		//servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
		addr.sin_family = (AF_INET);
		if (0 != bind(ServSock, (struct sockaddr*)&addr, sizeof(addr)))
		{
			printf("ipv4 Bind Failure:\n");
			fprintf(stderr, "socket() failed with error %d: %s\n", WSAGetLastError(), DecodeError(WSAGetLastError()));
			return -1;
		}
	}

	// 侦听
	if (listen(ServSock, 5) == SOCKET_ERROR)
	{
		fprintf(stderr, "listen() failed with error %d: %s\n", WSAGetLastError(), DecodeError(WSAGetLastError()));
		WSACleanup();
		return -1;
	}

	while (1)
	{
		printf("start accept....\n");
		//接受一个连接
		SOCKET ConnSock;
		ConnSock = accept(ServSock, (LPSOCKADDR)&From, &FromLen);
		if (ConnSock == INVALID_SOCKET)
		{
			fprintf(stderr, "accept() failed with error %d: %s\n", WSAGetLastError(), DecodeError(WSAGetLastError()));
			return -1;

		}

		// 收发数据
		SendAndRecv(ConnSock);
		// 关闭套接字
		closesocket(ConnSock);
	}

	return 0;
}


// 使用getaddrinfo函数的辅助来连接服务端
int CreateServerWithFuncgetaddrinfo(u_short Port, int nFamily)
{
	SOCKADDR_STORAGE From;
	int FromLen = sizeof(From);

	ADDRINFO Hints, *AddrInfo;
	memset(&Hints, 0, sizeof(Hints));

	Hints.ai_family = nFamily;
	Hints.ai_socktype = SOCK_STREAM;
	Hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
	// ai_flags 为AI_PASSIVE时,当节点名位NULL,则返回的地址将是通配地址
	// 如果节点名NULL,ai_flags不设置,则返回的地址将是回环地址。
	// AI_NUMERICHOST当此标志置位时,此标志表示调用中的节点名必须是一个数字地址字符串
	char strPort[32]; sprintf_s(strPort, sizeof(strPort), "%d", Port);
	int RetVal = getaddrinfo(NULL, strPort, &Hints, &AddrInfo);
	if ((RetVal != 0) || (AddrInfo==NULL))
	{
		fprintf(stderr, "getaddrinfo failed with error %d: %s\n", RetVal, gai_strerror(RetVal));
		return -1;
	}

	// 创建套接字
	SOCKET ServSock = socket(AddrInfo->ai_family, AddrInfo->ai_socktype, AddrInfo->ai_protocol);
	if (ServSock == INVALID_SOCKET)
	{

		fprintf(stderr, "socket() failed with error %d: %s\n",WSAGetLastError(), DecodeError(WSAGetLastError()));
		return -1;
	}

	// 绑定套接字
	if (bind(ServSock, AddrInfo->ai_addr, AddrInfo->ai_addrlen) == SOCKET_ERROR)
	{
		fprintf(stderr, "bind() failed with error %d: %s\n",WSAGetLastError(), DecodeError(WSAGetLastError()));
		return -1;
	}

	// 侦听
	if (listen(ServSock, 5) == SOCKET_ERROR)
	{
		fprintf(stderr, "listen() failed with error %d: %s\n", WSAGetLastError(), DecodeError(WSAGetLastError()));
		WSACleanup();
		return -1;
	}

	while (1)
	{
		printf("start accept....\n");
		//接受一个连接
		SOCKET ConnSock;
		ConnSock = accept(ServSock, (LPSOCKADDR)&From, &FromLen);
		if (ConnSock == INVALID_SOCKET)
		{
			fprintf(stderr, "accept() failed with error %d: %s\n", WSAGetLastError(), DecodeError(WSAGetLastError()));
			return -1;

		}

		// 收发数据
		SendAndRecv(ConnSock);
		// 关闭套接字
		closesocket(ConnSock);
	}
	return 0;
}


// 读取配置文件
void ReadInfoFromIni()
{
	// 数据初始化
	memset(&g_stServerInfo, 0x00, sizeof(g_stServerInfo));

	// 修改文件的路径为../conf/
	char szIniName[MAX_PATH];	// 配置文件的全名称 
	memset(szIniName, 0x00, sizeof(szIniName));
	strcpy_s(szIniName, "./server.ini");


	// 协议栈
	int nFamily = GetPrivateProfileIntA("IP_FAMILY", "FAMILY", 1, szIniName);
	if (0 == nFamily)
	{
		g_stServerInfo.nIPFamily = AF_INET;
	}
	else if (2 == nFamily)
	{
		g_stServerInfo.nIPFamily = AF_INET6;
	}
	else
	{
		g_stServerInfo.nIPFamily = AF_INET;
		// 判断机器是否支持IPV6
		int nIPV6Suport = ExistIPV6();
		if (nIPV6Suport)
		{
			g_stServerInfo.nIPFamily = AF_INET6;
		}
	}

	// 创建连接的方法
	g_stServerInfo.nMethod = GetPrivateProfileIntA("MODE", "METHOD", 0, szIniName);

	// 读取端口信息
	g_stServerInfo.nPort = GetPrivateProfileIntA("SERVER", "PORT", 0, szIniName);
}





int _tmain(int argc, _TCHAR* argv[])
{
	WSADATA wsaData;

	int RetVal = WSAStartup(MAKEWORD(1, 1), &wsaData);
	// 启动Winsock
	if (RetVal != 0)
	{
		fprintf(stderr, "WSAStartup failed with error %d: %s\n", RetVal, DecodeError(RetVal));
		return -1;
	}

	//CreateServer(9527, AF_INET6);
	//CreateServer(9527, AF_INET);
	
	// 读取配置文件
	ReadInfoFromIni();

	// 开启服务
	if (1 == g_stServerInfo.nMethod)
	{
		CreateServerWithFuncgetaddrinfo(g_stServerInfo.nPort, g_stServerInfo.nIPFamily);
	} 
	else
	{
		CreateServerWithCommon(g_stServerInfo.nPort, g_stServerInfo.nIPFamily);
	}

	WSACleanup();
	while (true)
	{
		getchar();
	}

	return 0;
}

 

// 追加双栈函数

// 双栈
int CreateServerWithDualStack(u_short Port)
{
	ADDRINFO Hints, *AddrInfo;
	memset(&Hints, 0, sizeof(Hints));

	Hints.ai_family = AF_UNSPEC;
	Hints.ai_socktype = SOCK_STREAM;
	Hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
	// ai_flags 为AI_PASSIVE时,当节点名位NULL,则返回的地址将是通配地址
	// 如果节点名NULL,ai_flags不设置,则返回的地址将是回环地址。
	// AI_NUMERICHOST当此标志置位时,此标志表示调用中的节点名必须是一个数字地址字符串
	char strPort[32]; sprintf_s(strPort, sizeof(strPort), "%d", Port);
	int RetVal = getaddrinfo(NULL, strPort, &Hints, &AddrInfo);
	if ((RetVal != 0) || (AddrInfo == NULL))
	{
		fprintf(stderr, "getaddrinfo failed with error %d: %s\n", RetVal, gai_strerror(RetVal));
		return -1;
	}


	// 创建套接字
	SOCKET listen_socks[64];
	SOCKET socks_type[64];
	int maxfd = 0;
	int listen_sock_num = 0;
	int on = 1;
	for (struct addrinfo* aip = AddrInfo; aip != NULL; aip = aip->ai_next) //显示获取的信息
	{
		if (listen_sock_num > 64)
		{
			break;
		}
		int type = 0;

		// 创建套接字
		SOCKET ServSock = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol);
		unsigned long nonblocking = 1;
		if (ioctlsocket(ServSock, FIONBIO, &nonblocking) != 0)
		{
			printf("set FIONBIO error\n");
			closesocket(ServSock);
			continue;
		}
		on = 1;
		if (setsockopt(ServSock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) != 0)
		{
			printf("set SO_REUSEADDR error\n");
			continue;
		}

		// ipv4
		if (aip->ai_family == AF_INET)
		{
		}
		else// ipv6
		{
			// unix 下使用
			on = 1;
			if (setsockopt(ServSock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof(on)) != 0)
			{
				printf("set IPV6_V6ONLY error\n");
				continue;
			}
		}

		// 绑定套接字
		if (bind(ServSock, aip->ai_addr, aip->ai_addrlen) == SOCKET_ERROR)
		{
			fprintf(stderr, "bind() failed with error %d: %s\n", WSAGetLastError(), DecodeError(WSAGetLastError()));
			continue;
		}

		// 侦听
		if (listen(ServSock, 5) == SOCKET_ERROR)
		{
			fprintf(stderr, "listen() failed with error %d: %s\n", WSAGetLastError(), DecodeError(WSAGetLastError()));
			continue;
		}

		listen_socks[listen_sock_num] = ServSock;
		socks_type[listen_sock_num] = aip->ai_family;
		listen_sock_num++;
	}

	// 释放内存
	freeaddrinfo(AddrInfo);

	// 取得最大句柄,Unix-like系统使用
	for (int i = 0; i < listen_sock_num; i++)
	{
		if ((int)listen_socks[i] > maxfd)
		{
			maxfd = (int)listen_socks[i];
		}
	}

	while (1)
	{
		SOCKADDR_STORAGE From;
		int FromLen = sizeof(From);
		fd_set accept_fds;
		FD_ZERO(&accept_fds);
		for (int i = 0; i < listen_sock_num; i++)
		{
			FD_SET(listen_socks[i], &accept_fds);
		}
		int ret = select(maxfd, &accept_fds, NULL, NULL, NULL);
		SOCKET AcceptSock = INVALID_SOCKET;
		int type = 0;
		for (int i = 0; i < listen_sock_num; i++) 
		{
			if (!FD_ISSET(listen_socks[i], &accept_fds))
			{
				continue;
			}
			AcceptSock = listen_socks[i];
			type = socks_type[i];
			break;
		}

		printf("start accept....%d\n", AcceptSock);

		//接受一个连接
		SOCKET ConnSock = accept(AcceptSock, (LPSOCKADDR)&From, &FromLen);
		if (ConnSock == INVALID_SOCKET)
		{
			fprintf(stderr, "accept() failed with error %d: %s\n", WSAGetLastError(), DecodeError(WSAGetLastError()));
			Sleep(5000);
			continue;
		}

		//struct linger linger;
		//linger.l_onoff = 1;
		//linger.l_linger = 0;
		//int optlen = sizeof(linger);
		//if (setsockopt(ConnSock, SOL_SOCKET, SO_LINGER, (char*)&linger, optlen) != 0)
		//{
		//	fprintf(stderr, "SO_LINGER can't set linger\n");
		//}

		char buf[128] = {0};
		if (type == AF_INET6)
		{
			struct sockaddr_in6* their_addr = (struct sockaddr_in6 *)&From;
			printf("server: got connection from %s, port %d, socket %d\n",
				inet_ntop(AF_INET6, &(their_addr->sin6_addr), buf, sizeof(buf)),
				their_addr->sin6_port, ConnSock);
		}
		else
		{
			struct sockaddr_in* their_addr = (struct sockaddr_in *)&From;
			printf("server: got connection from %s, port %d, socket %d\n",
				inet_ntop(AF_INET, &(their_addr->sin_addr), buf, sizeof(buf)),
				their_addr->sin_port, ConnSock);
		}
		
		// 收发数据
		SendAndRecv(ConnSock);
		// 关闭套接字
		closesocket(ConnSock);
	}

	return 0;
}

  

 

posted @ 2020-10-11 18:54  雪域蓝心  阅读(207)  评论(0编辑  收藏  举报