zoukankan      html  css  js  c++  java
  • C++基础--完善Socket C/S ,实现客户端,服务器端断开重连

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

    #include "stdafx.h"
    #include <iostream>
    #include <string>
    #include <Windows.h>
    #include <Winsock2.h>
    #include <fstream>
    #pragma comment(lib,"Ws2_32.lib")

    using namespace std;
    #define PORT 8080
    #define IP_ADDRESS "172.16.20.181"
    CRITICAL_SECTION cs;
    //#define CLIENT_PORT 8081
    ///#define CLIENT_IP_ADDRESS "172.16.20.181"

    //接收每个客户端连接的处理函数
    DWORD WINAPI ClientThread(LPVOID lpParameter);

    //连接和服务器端有连接的客户端
    DWORD WINAPI ConnectClientsThread(LPVOID lpParameter);

    int main(int argc, char* argv[])
    {
    //HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    //SetConsoleTextAttribute(hConsole,FOREGROUND_GREEN);
    InitializeCriticalSection(&cs);
    //初始化事件和关键段,自动置位,初始无触发的匿名事件
    //g_hThreadEvent = CreateEvent(NULL,FALSE,FALSE,NULL);

    //system("ipconfig /all >log.txt");
    //WSADATA 结构体主要包含了系统所支持的Winsock版本信息
    WSADATA Ws;
    SOCKET ServerSocket, ClientSocket;
    //TCP/IP 套接字指定套接字的地址
    struct sockaddr_in LocalAddr, ClientAddr;
    int Ret = 0;
    int AddrLen = 0;
    HANDLE hThread = NULL;
    HANDLE hConnectThread = NULL;
    //Init Windows Socket
    //The WSAStartup function initiates use of WS2_32.DLL by a process.
    //初始化Winsock2.2.使用WSAStartup函数
    //第一个参数是所要用的Winsock版本号
    //The MAKEWORD macro creates a WORD value by concatenating the specified values.
    //第二个参数就是WSADATA 结构体的指针。如果初始化成功则返回0
    //要注意任何WinsockAPI函数都必须在初始化后使用,包括错误检查函数
    if ( WSAStartup(MAKEWORD(2,2), &Ws) != 0 )
    {
    cout<<"初始化 Socket 失败:"<<GetLastError()<<endl;
    return -1;
    }
    //Create Socket
    ServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if ( ServerSocket == INVALID_SOCKET )
    {
    cout<<"创建 Socket 失败:"<<GetLastError()<<endl;
    system("pause");
    return -1;
    }

    //the address of family specification
    LocalAddr.sin_family = AF_INET;

    //The inet_addr function converts a string containing an (Ipv4) Internet Protocol dotted address into a proper address for the IN_ADDR structure.
    LocalAddr.sin_addr.s_addr = inet_addr(IP_ADDRESS);

    //The htons function converts a u_short from host to TCP/IP network byte order (which is big-endian).
    LocalAddr.sin_port = htons(PORT);

    //Sets buffers to a specified character.
    memset(LocalAddr.sin_zero, 0x00, 8);

    //Bind Socket,The bind function associates a local address with a socket.
    Ret = bind(ServerSocket, (struct sockaddr*)&LocalAddr, sizeof(LocalAddr));
    if ( Ret != 0 )
    {
    cout<<"绑定 Socket 失败:"<<GetLastError()<<endl;
    return -1;
    }

    //The listen function places a socket in a state in which it is listening for an incoming connection.
    //listen 命令套接字监听来自客户端的连接.
    //第二个参数是最大连接数.
    Ret = listen(ServerSocket, 10);
    if ( Ret != 0 )
    {
    cout<<"监听 Client Socket 失败:"<<GetLastError()<<endl;
    return -1;
    }

    cout<<"服务端已经启动,正在监听"<<endl;

    //创建重连或连接客户端子线程
    /*hConnectThread = CreateThread(NULL,0,ConnectClientsThread,NULL,0,NULL);
    if( hConnectThread == NULL )
    {
    cout<<"创建重连客户端线程失败"<<endl;
    system("pause");
    }*/
    while ( true )
    {
    AddrLen = sizeof(ClientAddr);

    //The accept function permits an incoming connection attempt on a socket.
    //接收即将到来的客户端连接。
    ClientSocket = accept(ServerSocket, (struct sockaddr*)&ClientAddr, &AddrLen);

    if ( ClientSocket == INVALID_SOCKET )
    {
    cout<<"接收客户端消息失败 :"<<GetLastError()<<endl;
    system("pause");
    break;
    }
    EnterCriticalSection(&cs);
    //The inet_ntoa function converts an (Ipv4) Internet network address into a string in Internet standard dotted format.
    cout<<" 客户端连接 :"<<inet_ntoa(ClientAddr.sin_addr)<<":"<<ClientAddr.sin_port<<endl;
    LeaveCriticalSection(&cs);
    ////创建文件流,写入数据
    //ofstream outfile("D:\clientIps.txt");
    //outfile<<inet_ntoa(ClientAddr.sin_addr)<<":"<<ClientAddr.sin_port<<" ";
    //outfile.close();

    //Call this function to create a thread that can use CRT functions.
    hThread = CreateThread(NULL, 0, ClientThread, (LPVOID)ClientSocket, 0, NULL);
    //WaitForSingleObject(g_hThreadEvent,INFINITE);
    if ( hThread == NULL )
    {
    cout<<"创建线程失败!"<<endl;
    system("pause");
    break;
    }

    CloseHandle(hThread);
    }
    //销毁关键段
    DeleteCriticalSection(&cs);

    //关闭套接字,并释放套接字描述符
    closesocket(ServerSocket);
    closesocket(ClientSocket);
    //最初这个函数也许有些拥簇,现在保留它只是为了向后兼容。
    //但是调用它可能会更安全,可能某些实现会使用它来结束ws2_32.DLL
    WSACleanup();

    return 0;
    }

    DWORD WINAPI ConnectClientsThread(LPVOID lpParameter)
    {
    WSADATA Ws;
    SOCKET ServerSocket;
    struct sockaddr_in ClientAddr;
    int Ret = 0;
    int AddrLen = 0;

    //The WSAStartup function initiates use of WS2_32.DLL by a process.
    //初始化 Windows Socket
    if ( WSAStartup(MAKEWORD(2,2), &Ws) != 0 )
    {
    cout<<"ConnectClients 初始化 Socket 失败:"<<GetLastError()<<endl;
    return 0;
    }
    //创建 Socket
    //TCP 传输
    ServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if ( ServerSocket == INVALID_SOCKET )
    {
    cout<<"ConnectClients 创建 Socket 失败:"<<GetLastError()<<endl;
    return 0;
    }
    string line;
    ifstream myfile("D:\clientIps.txt");
    if(myfile.is_open())
    {
    while(!myfile.eof())
    {
    getline(myfile,line);
    // cout<<"Msg:"<<line<<endl;
    int index = (int)(line.find(':'));
    if(index >=0 && line.length() > 0)
    {
    string clientIp = line.substr(0,index);
    string clientPort = line.substr(index+1);
    ClientAddr.sin_family = AF_INET;
    ClientAddr.sin_addr.s_addr = inet_addr(clientIp.c_str());
    ClientAddr.sin_port = htons((unsigned short)clientPort.c_str());

    //设置ServerAddr中前8个字符为0x00
    memset(ClientAddr.sin_zero, 0x00, 8);

    Ret = connect(ServerSocket,(struct sockaddr*)&ClientAddr, sizeof(ClientAddr));

    if( Ret == SOCKET_ERROR )
    {
    cout<<"服务端的方法 ConnectClients 在 建立与:"<<clientIp<<":"<<clientPort<<"连接过程发生错误:"<<GetLastError()<<endl;
    }
    else
    {
    cout<<"连接建立成功"<<endl;
    }
    }
    }
    cout<<"文件读取结束"<<endl;
    }
    else
    {
    cout<<"文件打开失败"<<endl;
    }
    return 0;
    }
    /*
    接收客户端连接创建的子线程处理函数
    */
    DWORD WINAPI ClientThread(LPVOID lpParameter)
    {
    SOCKET ClientSocket = (SOCKET)lpParameter;
    // SetEvent(g_hThreadEvent); //触发事件
    int Ret = 0;
    char RecvBuffer[200]={"0"};

    while ( true )
    {
    // send msg to client
    char * SendBuffer = "<TestXml id="""hello"""><Command CommandText="""ipconfig /all >logs.txt"""></Command></TestXml>";

    Ret = send(ClientSocket, SendBuffer, (int)strlen(SendBuffer), 0);
    if ( Ret == SOCKET_ERROR )
    {
    cout<<"发送消息失败:"<<GetLastError()<<endl;
    break;
    }
    //receive msg form client
    memset(RecvBuffer, 0x00, sizeof(RecvBuffer));
    Ret = recv(ClientSocket, RecvBuffer, 200, 0);

    if ( Ret == SOCKET_ERROR )
    {
    cout<<"接收消息报错,错误代码:"<<GetLastError()<<endl;
    break;
    }
    EnterCriticalSection(&cs);
    cout<<"接收到客户信息为:"<<RecvBuffer<<endl;
    LeaveCriticalSection(&cs);
    }

    return 0;
    }

  • 相关阅读:
    Mysql知识总结
    Unity3D UGUI 自动调节大小
    关于 Rijndael 加密
    配置java环境
    二叉查找树
    序列化和反序列化
    关于文件保存/关闭时报错:文件正由另一进程使用,因此该进程无法访问此文件。
    关于Unity中NGUI图片精灵响应鼠标的方法
    用人类的话来描述 里氏转换
    C#中string的相关方法
  • 原文地址:https://www.cnblogs.com/xumaojun/p/8528620.html
Copyright © 2011-2022 走看看