zoukankan      html  css  js  c++  java
  • Socket编程--基础(基本server/client实现)

    • IPv4套接口地址结构
      •   IPv4套接口地址结构通常也称为“网际套接字地址结构”,它以“sockaddr_in”命名,定义在头文件中
      •   LINUX结构下的常用结构,一般创建套接字的时候都要将这个结构里面的值进行初始化
      • struct sockaddr_in  
        {  
            sa_family_t    sin_family; /* address family: AF_INET */ 
            in_port_t      sin_port;   /* port in network byte order(网络字节序) */ 
            struct in_addr sin_addr;   /* internet address */ 
        };  
        /* Internet address. */ 
        struct in_addr  
        {  
            uint32_t       s_addr;     /* address in network byte order */ 
        };  
    • socket函数 
      • #include <sys/types.h>  
        #include <sys/socket.h>  
        int socket(int domain, int type, int protocol);  

        //创建一个套接字用于通信 参数分析
        domain:指定通信协议族(protocol family),常用取值AF_INET(IPv4)
        type:指定socket类型, 流式套接字SOCK_STREAM,数据报套接字SOCK_DGRAM,原始套接字SOCK_RAW
        protocol:协议类型,常用取值0, 使用默认协议
        返回值:
        成功: 返回非负整数,套接字;
        失败: 返回-1
    • bind函数
      • int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);  //addrlen--地址长度
        绑定一个本地地址到套接字。绑定函数
        参数:
        sockfd:socket函数返回的套接字
        addr:要绑定的地址
    • listen函数
      • int listen(int sockfd, int backlog);
          listen函数应该用在调用socket和bind函数之后, 并且用在调用accept之前, 用于将一个套接字从一个主动套接字转变成为被动套接字。
        使得一个进程可以接受其它进程的请求,从而成为一个服务器进程。在TCP服务器编程中listen函数把进程变为一个服务器,并指定相应的套接字变为被动连接。

        sockfd 一个已绑定未被连接的套接字描述符
        backlog说明:
        对于给定的监听套接口,内核要维护两个队列:
        1、已由客户发出并到达服务器,服务器正在等待完成相应的TCP三路握手过程(SYN_RCVD状态)
        2、已完成连接的队列(ESTABLISHED状态)
        但是两个队列长度之和不能超过backlog


        
        
    • accept函数
      • int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

        sockfd:服务器套接字
        addr:将返回对等方的套接字地址, 不关心的话, 可以设置为NULL
        addrlen:返回对等方的套接字地址长度, 不关心的话可以设置成为NULL, 否则一定要初始化
    • connect函数
      • int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

        建立一个连接至addr所指定的套接字
        参数:
        sockfd:未连接套接字
        addr:要连接的套接字地址
        addrlen:第二个参数addr长度
    • inet_aton
      •   将一个字符串的ip地址字节转换成了一个一个32位的网络序列IP地址
        int inet_aton(const char *string, struct in_addr*addr);

        string是表示的是要转换的字符串ip地址,后面的是网络序列ip地址
        成功返回非0,不成功返回-1
    • 客户端和服务器端练习(serverclient)
      •   分别建立两个工程,一个server,一个client。然后先打开服务端,再打开客户端进行测试,源代码如下。
        //服务器端
        #pragma comment(lib,"ws2_32.lib")
        #include<iostream>
        #include<winsock2.h>
        #include<string>
        #include<stdio.h>
        using namespace std;
        
        int main(){
            //创建套接字
            WORD myVersionRequest;
            WSADATA wsaData;                          //包含系统所支持的winsocket版本信息
            myVersionRequest = MAKEWORD(1, 1);        //初始化版本1.1
            int err;
            err = WSAStartup(myVersionRequest, &wsaData);
        
            if (!err){
                cout << "已经打开套接字" << endl;
            }
            else{
                //进一步绑定套接字
                cout << "套接字未打开" << endl;
                return 0;
            }
        
            //创建可识别套接字  调用socket函数
            SOCKET serSocket = socket(AF_INET, SOCK_STREAM, 0);
        
            //需要绑定的参数
            SOCKADDR_IN addr;
            addr.sin_family = AF_INET;
            addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//ip地址
            addr.sin_port = htons(3000);//绑定端口
        
            //将套接字绑定到指定的网络地址
            bind(serSocket, (SOCKADDR*)&addr, sizeof(SOCKADDR));//绑定完成
            //监听连接
            listen(serSocket, 10);                               //第二个参数代表能够接受的最多的连接数
            //建立客户端的连接
            SOCKADDR_IN clientsocket;
            int len = sizeof(SOCKADDR);
            SOCKET serConn;
            //等待客户端的连接
            serConn = accept(serSocket, (SOCKADDR*)&clientsocket, &len);      //返回一个数字  接受函数,不是-1就是接受连接成功
            cout << "客户端" << inet_ntoa(clientsocket.sin_addr) << "已连接" << endl;             //客户端已连接
        
            while (1) {
                char sendBuf[100];                              //发送的字节
                sprintf_s(sendBuf, "server : welcome %s to server.", inet_ntoa(clientsocket.sin_addr));    //转换函数,将二进制的ip序列转换成char数组
                //在对应的IP处并且将这行字打印到那里
                send(serConn, sendBuf, strlen(sendBuf) + 1, 0);
                char receiveBuf[100];                          //收到的字节
                //接收客户端传来的信息
                recv(serConn, receiveBuf, strlen(receiveBuf) + 1, 0);
                char* quit = "quit";
                //如果客户端传来了quit信号,则服务端关闭,客户端也关闭
                if (!strcmp(receiveBuf, quit)) {
                    break;
                }
                printf("%s
        ", receiveBuf);
            }
        
            closesocket(serConn);   //关闭
            WSACleanup();           //释放资源的操作
        }
        //客户端
        #pragma comment(lib,"ws2_32.lib")
        #include<winsock2.h>
        #include<iostream>
        #include<string>
        #include<conio.h>
        using namespace std;
        int main(){
        
            WORD versionRequired;
            WSADATA wsaData;                            //包含系统所支持的WinStock版本信息
            versionRequired = MAKEWORD(1, 1);           //初始化版本1.1
            int err;
            //注册WinStock,返回状态
            err = WSAStartup(versionRequired, &wsaData);//协议库的版本信息
            if (!err)   {                                //返回结果为0表示初始化失败{
                cout << LPSTR("客户端套接字已经打开!
        ");
        }
            else{
                //调用WSAGetLastError()查看错误信息
                cout << ("客户端套接字打开失败:") << WSAGetLastError() << endl;
                return 0;//结束
            }
            /*
            创建套接字:
            流式套接字:   SOCK_STREAM , IPPROTO_TCP
            数据报套接字:  SOCK_DGRAM  , IPPROTO_UDP
            */
        
            SOCKET clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);    //创建流式套接字
            SOCKADDR_IN clientsock_in;                                          //专门针对Internet 通信域的Winsock地址结构
            clientsock_in.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");        //通过inet_addr结构指定套接字的主机IP地址 
            clientsock_in.sin_family = AF_INET;                                 //指定协议家族:AF_INET
            clientsock_in.sin_port = htons(3000);                               //指定将要分配给套接字的传输层端口号:6000
        
            //开始连接
            int fail = connect(clientSocket, (SOCKADDR*)&clientsock_in, sizeof(SOCKADDR));
            if (fail){
                cout << "与服务端连接失败!程序将退出..." << endl;
                _getch();
                return 0;
            }
            string s;
            while (cin >> s){
                char receiveBuf[100];
                //接收数据
                recv(clientSocket, receiveBuf, 101, 0);
                cout << receiveBuf << endl;
                //发送数据
                send(clientSocket, s.c_str(), s.length() + 1, 0);
                if (s == "quit"){
                    break;
                }
            }
            closesocket(clientSocket);//关闭套接字
        
            if (WSACleanup() == SOCKET_ERROR){
                cout << "套接字关闭失败:" << WSAGetLastError() << endl;
            }
            else{
                cout << "套接字成功关闭." << endl;
            }
            _getch();
            return 0;
        }
      •   程序运行截图 

  • 相关阅读:
    lear for video
    My needs test
    jungle
    因文章很荣幸的被别人抄袭了,为了刚这种人,决定以后将文章都用英文发布出来
    atom 安装multi-cursor 插件 实现多行编辑
    Typora下使用markdown进行插入图片
    dockerhub/jenkins
    promethus grafana dingtalk pushgateway alertermanager
    关于自律比较好的一篇文章
    @WebService这个标签的作用是什么
  • 原文地址:https://www.cnblogs.com/Kobe10/p/5770139.html
Copyright © 2011-2022 走看看