socket C/C++编程(7)server端读取client端键入的数据

1. 服务器读取一次客户端编辑发送的数据

#ifdef WIN32
    #include 
#else
    #include 
    #include 
    #include 
    #include 
    #include 
#endif
#include 


int main(int argc, char *argv[]){

    // 初始化”ws2_32.lib”
    #ifdef WIN32
        WSADATA ws;
        WSAStartup(MAKEWORD(2,2), &ws);
    #endif

    // 创建第一类socket
    int sock = socket(AF_INET,SOCK_STREAM,0);
    if(sock == -1){
        printf("create sock error!\n");
        return -1;
    }

    // TCP Server指定端口并设置服务端端口的属性,返回(sockaddr*)&saddr

    unsigned short port = 8080; // 默认端口号
    if(argc > 1){
        port = atoi(argv[1]);
    }
    sockaddr_in saddr; // 声明端口
    saddr.sin_family = AF_INET; // TCPIP协议
    saddr.sin_port = htons(port); // 绑定端口号, htons()之host-to-network
    saddr.sin_addr.s_addr = 0; //或htonl(0) 服务器接受的IP地址 0表示接受任意内外网IP

    // 绑定端口到指定的socket,输入(sockaddr*)&saddr
    if(bind(sock, (sockaddr*)&saddr, sizeof(saddr))!=0){
        printf("OS bind socks to this port %d failed\n", port);
        return -2;
    }
    printf("OS bind this port %d to sockets successfully!\n", port);
    listen(sock, 10); // 允许用户连接函数(客户socket(一个客户一个socket),最大请求数队列的长度,)

    sockaddr_in caddr; // 结构体:存储客户端的相关信息:端口号和IP地址s
    socklen_t len = sizeof(caddr); 

    int client = accept(sock,(sockaddr*)&caddr,&len); // 第二类socket: 创建一个socket专门读取缓冲区clients(这里缓冲区大小如上行listen代码所示为10)
    printf("accept client %d", client);
    char *ip = inet_ntoa(caddr.sin_addr); // 客户端IP地址转字符串
    unsigned short cport = ntohs(caddr.sin_port);// 客户端端口号(网络字节序转本地字节序)
    printf("client ip: %s, port is %d\n", ip, cport); // 打印客户端连接信息

    char buf[1024] = {0};
    int lenRecv = recv(client,buf, sizeof(buf)-1,0); // server读取client端键入的数据(第二类socket的句柄,存储数据的地方,flag)
    printf("Recvd data: %s \n Len: %d \n", buf, lenRecv); // 服务器显示客户端键入的字符串长度

    #ifdef WIN32 // 读取数据的第二类socket创建后要记得关闭
        closesocket(client);
    #else
        close(client);       
    #endif

    //#ifdef WIN32 // 端口的第一类socket,不再交互后也要记得关闭,先二后一时堆栈思想
    //  closesocket(sock);
    //#else
    //    close(sock);       
    //#endif



    getchar();
    return 0;
}

客户端发送数据,如下图,

socket C/C++编程(7)server端读取client端键入的数据_第1张图片

服务端接收数据,如下图,

socket C/C++编程(7)server端读取client端键入的数据_第2张图片

但是,问题是客户端只能发送一次。下一步,我们允许客户端多次发送,服务器端多次接收,直到收到客户端“quit”字符串为止。

2. 服务器持续读取客户端编辑发送的数据

#ifdef WIN32
    #include 
#else
    #include 
    #include 
    #include 
    #include 
    #include 
#endif
#include 
#include 


int main(int argc, char *argv[]){

    // 初始化”ws2_32.lib”
    #ifdef WIN32
        WSADATA ws;
        WSAStartup(MAKEWORD(2,2), &ws);
    #endif

    // 创建第一类socket
    int sock = socket(AF_INET,SOCK_STREAM,0);
    if(sock == -1){
        printf("create sock error!\n");
        return -1;
    }

    // TCP Server指定端口并设置服务端端口的属性,返回(sockaddr*)&saddr

    unsigned short port = 8080; // 默认端口号
    if(argc > 1){
        port = atoi(argv[1]);
    }
    sockaddr_in saddr; // 声明端口
    saddr.sin_family = AF_INET; // TCPIP协议
    saddr.sin_port = htons(port); // 绑定端口号, htons()之host-to-network
    saddr.sin_addr.s_addr = 0; //或htonl(0) 服务器接受的IP地址 0表示接受任意内外网IP

    // 绑定端口到指定的socket,输入(sockaddr*)&saddr
    if(bind(sock, (sockaddr*)&saddr, sizeof(saddr))!=0){
        printf("OS bind socks to this port %d failed\n", port);
        return -2;
    }
    printf("OS bind this port %d to sockets successfully!\n", port);
    listen(sock, 10); // 允许用户连接函数(客户socket(一个客户一个socket),最大请求数队列的长度,)

    sockaddr_in caddr; // 结构体:存储客户端的相关信息:端口号和IP地址s
    socklen_t len = sizeof(caddr); 

    int client = accept(sock,(sockaddr*)&caddr,&len); // 第二类socket: 创建一个socket专门读取缓冲区clients(这里缓冲区大小如上行listen代码所示为10)
    printf("accept client %d", client);
    char *ip = inet_ntoa(caddr.sin_addr); // 客户端IP地址转字符串
    unsigned short cport = ntohs(caddr.sin_port);// 客户端端口号(网络字节序转本地字节序)
    printf("client ip: %s, port is %d\n", ip, cport); // 打印客户端连接信息

    char buf[1024] = {0};
    for(;;){
        int lenRecv = recv(client,buf, sizeof(buf)-1,0); // server读取client端键入的数据(第二类socket的句柄,存储数据的地方,flag)
        if(lenRecv <= 0) break;
        buf[lenRecv] = '\0'; // 客户端键入数据的末尾两位赋值‘、0’
        if(strstr(buf,"quit")!= NULL){
            break; // 字符串匹配函数,匹配到用户发送了"quit"
        }
        printf("Recvd data: %s \n Len: %d \n", buf, lenRecv); // 服务器显示客户端键入的字符串长度
    }

    #ifdef WIN32 // 读取数据的第二类socket创建后要记得关闭
        closesocket(client);
    #else
        close(client);       
    #endif

    //#ifdef WIN32 // 端口的第一类socket,不再交互后也要记得关闭,先二后一时堆栈思想
    //  closesocket(sock);
    //#else
    //    close(sock);       
    //#endif



    getchar();
    return 0;
}

客户端可以持续地发送数据,直到发送“quit”截止与服务器端的第二类socket,如下图,

socket C/C++编程(7)server端读取client端键入的数据_第3张图片

服务器端持续地接受数据,如下图,

socket C/C++编程(7)server端读取client端键入的数据_第4张图片

但是,现在有一个问题,就是两个或者两个以上clients同时接入,只有第一个client发送的数据能被服务器接收到,第二个client发送的数据是不被接收的。下一步,采用服务器端多线程同步获取clients的键入数据。

你可能感兴趣的:(计算机网络)