基于Select模型的通信仿真--win32编程代码

基于Select模型的通信仿真--win32编程代码

编程环境

Visual C++ 6.0

服务端

#include<stdio.h>
#include<string.h>
#include<WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
	AllocConsole();
	freopen("CONOUT$","w",stdout);
	freopen("CONIN$", "r", stdin);
    freopen("CONOUT$", "w", stderr);
	// 初始化 Winsock
	WSADATA wsaData;
	int result=WSAStartup(MAKEWORD(2, 2), &wsaData);

	if (result != 0) 
	{
		 printf("WSAStartup failed with error: %d\n", result);
		 return 1;
	}

	//1.创建socket套接字
	/*
	SOCKET socket(
    _In_ int af,		//协议地址簇	IPv4:AF_INET/IPv6:AF_INET6
    _In_ int type,		//类型			流式协议:SOCK_STREAM/数据报协议:SOCK_DGRAM
    _In_ int protocol	//保护协议		上层协议tcp、udp不用写,填0即可
    );
	*/
	SOCKET listen_socket=socket(AF_INET, SOCK_STREAM, 0);
	if (INVALID_SOCKET==listen_socket)
	{
		printf("create listen socket failed!!! errcode: %d\n", GetLastError());
		WSACleanup();
		return -1;
	}

	//2.给socket绑定端口号
	/*
	* ip地址结构体
	struct sockaddr_in {
	ADDRESS_FAMILY sin_family;	//协议地址簇
    USHORT sin_port;			//端口号	2字节
    IN_ADDR sin_addr;			//ip地址	4字节
    CHAR sin_zero[8];			//保留字节	8字节
	};
	struct sockaddr {
	u_short sa_family;					//协议地址簇
	CHAR sa_data[14];                   //14字节
	}
	*/
	struct sockaddr_in local = {0};

	local.sin_family = AF_INET;
	local.sin_port = htons(8080);//绑定端口 大小端转化:中间设备使用大端序(路由器),但是电脑使用的是小端序,所以要转化
	/*
	电脑上有多个网卡,服务器可以选择接收哪个或哪些网卡传过来的数据。
	如:127.0.0.1(本地环回),则服务器只能和自己通信	INADDR_LOOPBACK
	一般写全0地址(0.0.0.0),表示接收全部网卡的数据	INADDR_ANY
	*/
	//local.sin_addr.s_addr = htonl(INADDR_ANY);//接收全部网卡的数据 大小端转化
	local.sin_addr.s_addr = inet_addr("0.0.0.0");//接收全部网卡的数据 字符串ip转成整数ip

	/*
	int bind(
    SOCKET s,							//绑定的套接字
    const struct sockaddr FAR * name,	//ip地址结构体
    int namelen							//ip地址结构体的长度
    );
	*/
	bind(listen_socket,(struct sockaddr*)&local,sizeof(local));

	//3.给socke开启监听属性,只用来接收连接
	/*
	int listen(
    _In_ SOCKET s,		//监听套接字
    _In_ int backlog	//
    );
	*/
	if (-1 == listen(listen_socket, 10))
	{
		printf("start listen failed!!! errcode: %d\n", GetLastError());
		WSACleanup();
		return -1;
	}
    fd_set redset;
    //4、初始化文件描述符集合  
    FD_ZERO(&redset);
    //5、添加要检测的监听文件描述符    
    FD_SET(listen_socket,&redset);

    
    printf("This is SERVER!\n");
    while (1)
    {
        fd_set tmp = redset;
        /* 6、不停地检测文件描述符
              6.1 超时  select() = 0 再次检测或关闭套接字
              6.2 异常  select() = -1 异常处理
              6.3 成功  selct() >0
       */
        printf("selecting...\n");
        int ret = select(-1, &tmp, NULL, NULL, NULL);
        if (ret <= 0)
        {
            printf("select failed!!! errcode: %d\n", GetLastError());
            closesocket(listen_socket);
            WSACleanup();
            return -1;
        }
       // printf("select = %d\n",ret);
        //7、判断文件描述符属于哪一类
            //通过将原来redset集合中的文件描述符与select处理过的tmp集合比较,判断哪些文件描述符就绪,如果就绪,是哪一类
        for (int i = 0; i < (int)redset.fd_count; i++)
        {
            if (FD_ISSET(redset.fd_array[i], &tmp))//判断文件描述符(套接字)i的读缓冲区是否有数据
            {
                //就绪文件描述符是监听描述符
                if (redset.fd_array[i] == listen_socket)    // 监听套接字接收到新连接
                {
                    if (redset.fd_count < FD_SETSIZE)
                    {
                        sockaddr_in addrRemote;
                        int nAddrLen = sizeof(addrRemote);
                        //接收客户端的连接请求
                        SOCKET client_socket = ::accept(listen_socket, (SOCKADDR*)&addrRemote, &nAddrLen);
                        FD_SET(client_socket, &redset);
                        printf("与主机 %s 建立连接\n", inet_ntoa(addrRemote.sin_addr));
                    }
                    else
                    {
                        printf("Too much connections!\n");
                        continue;
                    }
                }
                else//就绪文件描述符不是监听描述符,是通信描述符
                {
                    //接收信息
                    char rbuffer[1024] = { 0 };
                    int len = recv(redset.fd_array[i], rbuffer, 1024, 0);

                    if (len <= 0)
                    {
                        printf("The client %d has disconnected.\n", i);
                        FD_CLR(redset.fd_array[i], &redset);
                        shutdown(redset.fd_array[i], SD_BOTH);
                        closesocket(redset.fd_array[i]);
                        break;
                    }
                    printf("recive from client%d:\t%s\n", i, rbuffer);

                    //发送信息
                    char sbuffer[1024] = { 0 };
                    // 检查接收到的消息
                    if (strcmp(rbuffer, "计算从1到100的奇数和") == 0)
                    {
                        int sum = 0;
                        for (int j = 1; j <= 100; j += 2)
                        {
                            sum += j;
                        }
                        printf("send to client%d:\t1到100的奇数和是 %d\n", i, sum);

                        sprintf(sbuffer, "1到100的奇数和是 %d\n", sum);
                    }
                    else
                    {
                        printf("send to client%d:\tunknow!\n", i);
                        sprintf(sbuffer, "unknow!");
                    }

                    len = send(redset.fd_array[i], sbuffer, strlen(sbuffer), 0);
                    if (len == -1)
                    {
                        perror("send error");
                        exit(1);
                    }
                   
                }
            }
        }
    }

    closesocket(listen_socket);
	FreeConsole();
	// 清理 Winsock
    WSACleanup();


	return 0;
}

客户端

#include<stdio.h>
#include<WinSock2.h>
#pragma comment(lib,"ws2_32.lib")

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
	AllocConsole();
	freopen("CONOUT$","w",stdout);
	freopen("CONIN$", "r", stdin);
    freopen("CONOUT$", "w", stderr);
	// 初始化 Winsock
	WSADATA wsaData;
	int result=WSAStartup(MAKEWORD(2, 2), &wsaData);

	if (result != 0) 
	{
		 printf("WSAStartup failed with error: %d\n", result);
		 return 1;
	}

	//1.创建socket套接字
	SOCKET client_socket = socket(AF_INET, SOCK_STREAM, 0);
	if (INVALID_SOCKET == client_socket)
	{
		printf("create socket failed!!! errcode: %d\n", GetLastError());
		WSACleanup();
		return -1;
	}
	//2.连接服务器
	struct sockaddr_in target;//目标服务器的ip结构体
	target.sin_family = AF_INET;
	target.sin_port = htons(8080);
	target.sin_addr.s_addr = inet_addr("127.0.0.1");

	if (-1 == connect(client_socket, (struct sockaddr*)&target, sizeof(target)))
	{
		printf("connect server failed!!!\n");
		shutdown(client_socket, SD_BOTH);
		closesocket(client_socket);
		WSACleanup();
		return -1;
	}
	//3.开始通讯

	printf("This is  Cilent1.\n\n");
	while (1)
	{
		//发送信息
		printf("send:\t");
		char sbuffer[1024] = { 0 };
		scanf("%s", sbuffer);
		send(client_socket, sbuffer, strlen(sbuffer),0);

		//接收消息
		char rbuffer[1024] = { 0 };
		int ret=recv(client_socket, rbuffer, 1024, 0);
		if (ret <= 0)
		{
			break;//断开连接
		}
		printf("recive:\t%s\n", rbuffer);
	}
	
	//4.关闭连接
	shutdown(client_socket, SD_BOTH);shutdown(client_socket, SD_BOTH);
	closesocket(client_socket);
	
	FreeConsole();
	// 清理 Winsock
    WSACleanup();


	return 0;
}

相关链接

基于Select模型的通信仿真(详解)

https://www.cnblogs.com/wa2211lq/p/18553178

posted @ 2024-11-18 18:20  刘倩_网安2211  阅读(3)  评论(0编辑  收藏  举报