zoukankan      html  css  js  c++  java
  • socket,实现服务器和客户端对话

    服务器:

    #define _CRT_SECURE_NO_WARNINGS
    #include<stdio.h>
    #include<string>
    #include<WinSock2.h> //网络库用2.2版本 目前系统的最高版本
    #pragma comment(lib,"Ws2_32.lib") //加载动态连接库 x32.x64都是用ws2_32.lib这一个版本
    //上面为第二版 第一版头文件为WinSock.h 动态库为wsock32.lib
    using namespace std;


    int main()
    {
    /*调用的库版本 如果直接赋值2.1 则出错(WORD为短整型,2.1为浮点型)
    用该宏去储存,转到内存MAKEWORD(2,1)为258 转换成2进制为0001 0000 0010
    即将主版本号2,存放在低字节位(1个字节占8位),副版本号1,存放在高字节0001 <因为在内存中是小头方式存储 高位数据在前> */
    WORD m_versions = MAKEWORD(2,2); //MAKEWORD(A,B)参数1为副版本号,参数2为主版本号
    WSADATA m_data;//用于接受返回的socket信息

    //***1*** 打开网络库
    int answer = WSAStartup(m_versions, &m_data); //解析参数2 1为我们要使用的版本 2为系统能提供的最高版本 3为当前库的信息 4为打开结果 或当前套接字状态

    if (answer != 0)//打开失败的结果
    {
    switch (answer)
    {
    case WSASYSNOTREADY:
    printf("网络通信依赖的网络子系统还没有准备好。");
    break;
    case WSAVERNOTSUPPORTED:
    printf("系统不支持当前所需库版本。");
    break;
    case WSAEINVAL:
    printf("无法找到当前库版本所需DLL。");
    break;
    case WSAEPROCLIM:
    printf("当前端口数量已达限制。");
    break;
    case WSAEINPROGRESS:
    printf("当前初始化函数被阻塞。");
    break;
    case WSAEFAULT:
    printf("当前指针(参数2)为无效指针。");
    break;
    }
    }
    if (m_data.wVersion != 514) //即未能打开2.2版本 2.2版本以单字节存储即为十进制的514
    {//HIBYTE(m_data.wVersion)获取该成员的高字节(即高版本号) LOBYTE()获取该成员的低字节
    WSACleanup(); //未能打开指定版本,则关闭该网络库
    system("pause");
    return 0;
    }


    //***2*** 创建服务器socket 每个返回的值都是唯一的 返回的值为TCP/IP协议的总编号,代表着各协议的特点 。
    SOCKET m_ServerSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); //类似于MFC的窗口句柄,对该端口进行操作都需使用该套接字值
    //参数1地址类型(IPV4形式),2套接字类型(顺序,可靠,双向,基于连接的字节流),3协议的类型(TCP协议 与参数1对应)

    if (m_ServerSocket == INVALID_SOCKET)//创建失败
    {
    int m_ErrorNum=WSAGetLastError();
    printf("创建服务器socket失败,错误代码:%d ", m_ErrorNum);
    WSACleanup(); //未能打开指定版本,则关闭该网络库
    system("pause");
    return 0;
    }

    sockaddr_in m_ServerSocketaddr;//结构体,存储地址类型,地址和端口 (sockaddr_in与sockaddr结构一样,但前者方便赋值,后者方便作为参数传递)
    m_ServerSocketaddr.sin_family = AF_INET;//与创建时的地址类型相同
    m_ServerSocketaddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//将字符串形式转换成IP地址形式存储,127.0.0.1为回环地址,在本地(不出电脑)测试使用
    m_ServerSocketaddr.sin_port = htons(12345);//端口号 使用时应将其转换成主机字节顺序,且端口号是唯一的,不能重复绑定

    //***3*** 绑定对应的地址(找到电脑)和端口号(找到具体应用)
    int m_bind = bind(m_ServerSocket, (sockaddr *)&m_ServerSocketaddr, sizeof(m_ServerSocketaddr));
    if (m_bind !=0)//创建失败
    {
    int m_ErrorNum = WSAGetLastError();
    printf("绑定失败,错误代码:%d ", m_ErrorNum);
    closesocket(m_ServerSocket);
    WSACleanup();
    system("pause");
    return 0;
    }

    //***4*** 启动监听,监听是否有客户端连接(类似启动服务器 让客户端可以进行连接)
    int m_listen=listen(m_ServerSocket,5);//服务器的sockt。挂起连接队列最大长度(假设服务器能同时处理5个,现在进来了8个,剩下的进入队列等待处理)SOMAXCONN则让系统自行选择合适个数
    if (m_listen != 0)//启动失败
    {
    int m_ErrorNum = WSAGetLastError();
    printf("启动失败,错误代码:%d ", m_ErrorNum);
    closesocket(m_ServerSocket);
    WSACleanup();
    system("pause");
    return 0;
    }

    sockaddr_in m_ClientSocketaddr;//同步骤3一致,为存放客户端数据的结构体
    int m_ClientLen = sizeof(m_ClientSocketaddr);//结构体大小

    //***5*** 接受连接。当有客户端连接进来后,服务器为其创建一个socket,用于维持通信.参数2.3也可设置为NULL 不得到客户端的信息
    SOCKET m_ClientSocket = accept(m_ServerSocket, (sockaddr *)&m_ClientSocketaddr, &m_ClientLen);
    //accept函数会一直处于阻塞状态(等待连接),不会往下执行 且一次只能连一个,多个客户端连接则需要循环,且数量要相对应(否则一直阻塞)

    if (m_ClientSocket == INVALID_SOCKET)//返回的为无效socket
    {
    int m_ErrorNum = WSAGetLastError();
    printf("客户端连接失败,错误代码:%d ", m_ErrorNum);
    closesocket(m_ServerSocket);
    WSACleanup();
    system("pause");
    return 0;
    }
    printf("客户端连接成功 ");

    int a = 5;
    while (a!=0,a--)
    {

    //***6***接受客户端发送的数据
    char StoCbuf[1500] = { 0 };//用于存储服务器接受客户端发来的字符
    int a = sizeof(StoCbuf);
    int m_ClientStrLen = recv(m_ClientSocket, StoCbuf, sizeof(StoCbuf), 0); //1接受来自哪的sockt,存放在哪,放多少,读取方式(0为默认) 也会一直处于阻塞状态,直到客户端对其操作
    if (m_ClientStrLen == 0)//即客户端已下线
    {
    printf("连接中断,客户端已下线");
    }
    else if (m_ClientStrLen == SOCKET_ERROR)
    {
    int m_ErrorNum = WSAGetLastError();
    printf("接受客户端数据失败,错误代码:%d ", m_ErrorNum);
    break;
    }
    else
    {
    printf("客户端:%s ", StoCbuf);
    }


    //***7***给客户端发送数据
    printf("服务器:");
    gets(StoCbuf);
    int m_ServerStrLen = send(m_ClientSocket, StoCbuf, strlen(StoCbuf), 0);//目的socket,发送的数据,发送数据的长度,发送方式
    if (m_ServerStrLen == SOCKET_ERROR)
    {
    int m_ErrorNum = WSAGetLastError();
    printf("服务器发送数据失败,错误代码:%d ", m_ErrorNum);
    }

    if (strcmp(StoCbuf, "886") == 0)
    {
    printf("结束对话 ");
    break;
    }


    //使用完毕后,先销毁创建的套接字(该函数为网络库里面的函数),再关闭网络库
    closesocket(m_ServerSocket);
    WSACleanup();

    system("pause");
    }

    客户端:

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

    int main()
    {
    /*1打开网络库*/
    WORD m_versions = MAKEWORD(2, 2); //MAKEWORD(A,B)参数1为副版本号,参数2为主版本号
    WSADATA m_data;//用于接受返回的socket信息
    int answer=WSAStartup(m_versions,&m_data);
    if (answer != 0)//打开失败的结果
    {
    switch (answer)
    {
    case WSASYSNOTREADY:
    printf("网络通信依赖的网络子系统还没有准备好。");
    break;
    case WSAVERNOTSUPPORTED:
    printf("系统不支持当前所需库版本。");
    break;
    case WSAEINVAL:
    printf("无法找到当前库版本所需DLL。");
    break;
    case WSAEPROCLIM:
    printf("当前端口数量已达限制。");
    break;
    case WSAEINPROGRESS:
    printf("当前初始化函数被阻塞。");
    break;
    case WSAEFAULT:
    printf("当前指针(参数2)为无效指针。");
    break;
    }
    return 0;
    }
    if (m_data.wVersion != 514) //即未能打开2.2版本 2.2版本以单字节存储即为十进制的514
    {//HIBYTE(m_data.wVersion)获取该成员的高字节(即高版本号) LOBYTE()获取该成员的低字节
    WSACleanup(); //未能打开指定版本,则关闭该网络库
    system("pause");
    return 0;
    }

    /*2创建服务器socket*/
    SOCKET m_ServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //类似于MFC的窗口句柄,对该端口进行操作都需使用该套接字值
    //参数1地址类型(IPV4形式),2套接字类型(顺序,可靠,双向,基于连接的字节流),3协议的类型(TCP协议 与参数1对应)

    if (m_ServerSocket == INVALID_SOCKET)//创建失败
    {
    int m_ErrorNum = WSAGetLastError();
    printf("创建服务器socket失败,错误代码:%d ", m_ErrorNum);
    WSACleanup(); //未能打开指定版本,则关闭该网络库
    system("pause");
    return 0;
    }

    /*3连接到服务器*/
    sockaddr_in m_ServerMsg;//装载服务器信息
    m_ServerMsg.sin_family = AF_INET;//地址类型
    m_ServerMsg.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");//服务器IP地址 将字符串形式转换成IP地址形式存储,127.0.0.1为回环地址,在本地(不出电脑)测试使用
    m_ServerMsg.sin_port = htons(12345);//服务器的端口号 将网络字节序转换为主机字节序
    int m_connect = connect(m_ServerSocket, (sockaddr*)&m_ServerMsg, sizeof(m_ServerMsg));
    if (m_connect != 0)
    {
    int m_ErrorNum = WSAGetLastError();
    printf("连接服务器失败,错误代码:%d ", m_ErrorNum);
    closesocket(m_ServerSocket);//关闭创建的socket;
    WSACleanup(); //未能打开指定版本,则关闭该网络库
    system("pause");
    return 0;
    }
    printf("服务器连接成功 ");


    while (1)
    {
    /*4发送消息给服务器*/
    char CtoSbuf[1500] = { 0 };//客户端发送给服务器
    printf("客户端:");
    gets(CtoSbuf);
    int m_ServerStrLen = send(m_ServerSocket, CtoSbuf, strlen(CtoSbuf), 0);//目的socket,发送的数据,发送数据的长度,发送方式
    if (m_ServerStrLen == SOCKET_ERROR)
    {
    int m_ErrorNum = WSAGetLastError();
    printf("客户端发送数据失败,错误代码:%d ", m_ErrorNum);
    }

    /*5接受服务器发送的数据*/
    char StoCbuf[1500] = { 0 };//用于存储服务器发来的字符
    int m_ClientStrLen = recv(m_ServerSocket, StoCbuf, sizeof(StoCbuf), 0); //1接受来自哪的sockt,存放在哪,放多少,读取方式(0为默认) 也会一直处于阻塞状态,直到客户端对其操作
    if (m_ClientStrLen == 0)//即客户端已下线
    {
    printf("连接中断,服务器已关闭");
    }
    else if (m_ClientStrLen == SOCKET_ERROR)
    {
    int m_ErrorNum = WSAGetLastError();
    printf("接受客户端数据失败,错误代码:%d ", m_ErrorNum);
    break;
    }
    else
    {
    printf("服务器:%s ",StoCbuf);
    }

    if (strcmp(StoCbuf, "886") == 0)
    {
    printf("结束对话 ");
    break;
    }

    }


    closesocket(m_ServerSocket);//关闭创建的socket;
    WSACleanup(); //未能打开指定版本,则关闭该网络库
    system("pause");
    }  

    先运行服务器,再运行客户端,运行效果如下

  • 相关阅读:
    python列表转json树菜单
    lvm分区创建和扩容
    分布式网络概述
    mycat权威指南阅读笔记--序言1
    Mongodb副本集实现及读写分离
    线程和进程
    socket客户端怎么判断http响应数据的结束
    java遍历http请求request的所有参数实现方法
    Java中mongodb使用and和or的复合查询
    idea @Override is not allowed when implementing interface method
  • 原文地址:https://www.cnblogs.com/aaaguai/p/12052135.html
Copyright © 2011-2022 走看看