zoukankan      html  css  js  c++  java
  • TCP套接字编程实现

    一、基于TCP的套接字编程实现流程:
    1.  服务器端流程简介:
                (1)创建套接字(socket)
                (2)将套接字绑定到一个本地地址和端口上(bind)
                (3)将套接字设定为监听模式,准备接受客户端请求(listen)
                (4)阻塞等待客户端请求到来。当请求到来后,接受连接请求,返回一个新的对应于此客户端连接的套接字sockClient(accept)
                (5)用返回的套接字sockClient和客户端进行通信(send/recv);
                (6)返回,等待另一个客户端请求(accept)
                (7)关闭套接字(close)
    2.  客户端流程简介:
                (1)  创建套接字(socket)
                (2)  向服务器发出连接请求(connect)
                (3)  和服务器进行通信(send/recv)
                (4)  关闭套接字(close)
                                                                 
    二、 send和recv函数的理解:
      当调用socket创建套接字时,同时在内核中生成发送和接收缓冲区。
    • 设置为connect模式时(客户端模式),调用send会将用户自定义的buff中的数据拷贝到发送缓冲区,缓冲区数据的发送由TCP/IP模型完成;

    • 设置为listen模式时(服务器端模式),发送缓冲区不再使用,接收缓冲区只存放客户端的连接请求。而accpet函数返回的新建套接字sockfd会再生成两个新缓冲区,发送和接收缓冲区。当调用recv时,recv先等待sockfd的发送缓冲区中数据按协议传送完毕,再检查sockfd的接收缓冲区,如果接收缓冲区没有数据或正在传送,则recv等待;否则recv将接收缓冲区中的数据拷贝到用户定义的buff中(ps:当接收缓冲区中数据长度大于buff长度时,recv要调用多次才能完全拷贝完成)。recv返回的是每次实际拷贝的数据长度,若拷贝出错则返回SOCKET_ERROR,若网络中断则返回0。

    • send和recv只是从发送/接收缓冲区中拷贝数据,真正的读写数据是由TCP/IP协议完成的

    C++客户端/服务器端的简单实现:
    (1)Sever实现:
    #include <Winsock2.h>
    #include <cstdio>
    #include <iostream>
    #pragma comment(lib,"ws2_32.lib")
    int main()
    {
            //1. 加载socket函数库
            WSADATA wsaData;
            SOCKET sockServer;
            SOCKADDR_IN addrServer;
            SOCKET sockClient;
            SOCKADDR_IN addrClient;
            WSAStartup(MAKEWORD(2,2),&wsaData);     //加载套接字库
    
            //2. 创建套接字
            addrServer.sin_addr.S_un.S_addr = htonl(INADDR_ANY);      //INADDR_ANY表示任何IP,即允许所有的客户端连接到本地服务端
            addrServer.sin_family = AF_INET;          //设置为IP通信
            addrServer.sin_port = htons(6000);        //绑定端口6000
            sockServer = socket(AF_INET,SOCK_STREAM,0);       //创建流式套接字
            std::cout<<"创建套接字成功"<<std::endl;
    
            //3. 将套接字绑定到 固定IP和固定端口
            bind(sockServer, (SOCKADDR*)&addrServer,  sizeof(SOCKADDR));    //进行端口和IP地址的绑定
            std::cout<<"绑定套接字成功"<<std::endl;
    
            //4. 将套接字设置为监听模式,等待连接到来
            listen(sockServer,5);           //监听队列为5
            std::cout<<"监听连接中......"<<std::endl;
            int len = sizeof(SOCKADDR);
            char sendBuf[100];      //发送至客户端的字符串
            char recvBuf[100];       //接受客户端返回的字符串
    
            //5. 阻塞服务端的进程,直到有客户端连接为止
            sockClient = accept(sockServer,  (SOCKADDR*)&addrClient,  &len);  //sockClinet为返回的新的客户端连接
            std::cout<<"收到连接:"<<inet_ntoa(addrClient.sin_addr)<<std::endl;
    
            //6. 接收并打印客户端数据
            int recvlen = 0;
            if((recvlen = recv(sockClient,recvBuf,100,0)) > 0)
            {
            std::cout<<recvBuf<<std::endl;
            }
            send(sockClient, "Receive the Client Data", 23, 0);
    
            //7. 关闭socket
            closesocket(sockClient);
            WSACleanup();
            return 0;
    }

    (2)Client实现:

    #include <WinSock2.h>  
    #include <stdio.h>
    #include <iostream>  
    #include <cstring>
    #pragma comment(lib, “ws2_32.lib”)  
      
    int main()  
    {  
        //1. 加载套接字  
        WSADATA wsaData;   
        if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)  
        {  
            printf(”Failed to load Winsock”);  
            return;  
        }  
      
        //2. 创建套接字
        SOCKADDR_IN addrSrv;  
        addrSrv.sin_family = AF_INET;  
        addrSrv.sin_port = htons(6000);  //端口号6000
        addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); //访问的服务器IP  
        SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0);  //创建客户端套接字
      
        //3. 向服务器发出连接请求  
       if(connect(sockClient, (struct  sockaddr*)&addrSrv, sizeof(addrSrv)) == INVALID_SOCKET)
       {  
            std::cout<<"Connect failed:"<<WSAGetLastError()<<std::endl;  
            return;  
        }
    
        //4.接收和发送数据  
        char recvbuff[1024];  
        memset(recvbuff, 0, sizeof(recvbuff));
        recv(sockClient, recvbuff, sizeof(recvbuff), 0);  
        std::string sendbuf = "hello, this is a Client…";  
        send(sockClient, sendbuf.c_str(), sendbuf.size(), 0);  
      
        //5. 关闭套接字  
        closesocket(sockClient);  
        WSACleanup();  
        return 0;
    }  
  • 相关阅读:
    SNMP的安全隐患及对策
    jsp+servlet+Tomcat+mysql实现用户注册、登录、查看、修改实例之——信息修改
    jsp+servlet+Tomcat+mysql实现用户注册、登录、查看、修改实例之——信息查看
    jsp+servlet+Tomcat+mysql实现用户注册、登录、查看、修改实例之——用户删除
    多线程的陷阱
    安装部署FastDFS
    你的知识需要管理
    1、什么是接口测试
    2、接口测试流程
    软件测试生命周期
  • 原文地址:https://www.cnblogs.com/ladawn/p/8423556.html
Copyright © 2011-2022 走看看