网络套接字编程(TCP协议)

简单的TCP网络程序

int socket(int domain, int type, int protocol);

参数说明:

domain:创建套接字的域或者叫做协议家族,也就是创建套接字的类型。该参数就相当于struct sockaddr结构的前16个位。如果是本地通信就设置为AF_UNIX,如果是网络通信就设置为AF_INET(IPv4)或AF_INET6(IPv6)。

type:创建套接字时所需的服务类型。其中最常见的服务类型是SOCK_STREAM和SOCK_DGRAM,如果是基于UDP的网络通信,我们采用的就是SOCK_DGRAM,叫做用户数据报服务,如果是基于TCP的网络通信,我们采用的就是SOCK_STREAM,叫做流式套接字,提供的是流式服务。

protocol:创建套接字的协议类别。你可以指明为TCP或UDP,但该字段一般直接设置为0就可以了,设置为0表示的就是默认,此时会根据传入的前两个参数自动推导出你最终需要使用的是哪种协议。

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

参数说明:

sockfd:创建套接字返回的文件描述符
addr:网络相关的属性
addrlen:传入的addr的长度

服务器绑定

class TcpSever
{
    void init()
    {
        _lisSock = socket(AF_INET, SOCK_STREAM, 0);

        if (_lisSock == -1)
        {
            cout << "error socket" << endl;
            exit(1);
        }

        cout << "sucess socket" << endl;

        //创建服务器信息
        sockaddr_in server;
        socklen_t len = sizeof(server);
        server.sin_family = AF_INET;
        server.sin_port = htons(_port);

        _ip == "" ? server.sin_addr.s_addr = INADDR_ANY : inet_aton(_ip.c_str(), &server.sin_addr);

        //绑定服务器
        if (bind(_lisSock, (const sockaddr *)&server, len) == -1)
        {
            cout << "error bind" << endl;
            exit(1);

        }
        cout << "sucess bind" << endl;
   }

private:
    int _lisSock;    // 监听套接字
    string _ip;      // 服务器ip
    u_int16_t _port; // 服务器端口
};

服务端监听

int listen(int sockfd, int backlog);

参数说明:

sockfd:需要设置为监听状态的套接字对应的文件描述符。
backlog:全连接队列的最大长度。如果有多个客户端同时发来连接请求,此时未被服务器处理的连接就会放入连接队列,该参数代表的就是这个全连接队列的最大长度,一般不要设置太大,设置为5或10即可。

//监听_sock
if (listen(_lisSock, 5) == -1)
{
    cout << "error listen" << endl;
    exit(1);

}
cout << "sucess listen" << endl;

服务端获取连接

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

参数说明:

sockfd:特定的监听套接字,表示从该监听套接字中获取连接。
addr:对端网络相关的属性信息,包括协议家族、IP地址、端口号等。
addrlen:调用时传入期望读取的addr结构体的长度,返回时代表实际读取到的addr结构体的长度,这是一个输入输出型参数。

void load()
{
     //监听_sock
     if (listen(_lisSock, 5) == -1)
     {
         cout << "error listen" << endl;
         exit(1);

     }
     cout << "sucess listen" << endl;

     while (1)
     {
         sockaddr_in client;
         socklen_t len = sizeof(client);

         int sock = accept(_lisSock, (sockaddr *)&client, &len);
         if (sock == -1)
         {
             cout << "error sock" << endl;
             exit(1);

         }
         cout << "succes sock" << endl;
}

客户端连接服务器

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

参数说明:

sockfd:特定的套接字,表示通过该套接字发起连接请求。
addr:对端网络相关的属性信息,包括协议家族、IP地址、端口号等。
addrlen:传入的addr结构体的长度。

class TcpClient
{
    public:
    TcpClient(string serIp,uint16_t serPort):_serIp(serIp),_serPort(serPort)
    {}


    void start()
    {
        //套接字
        int _sock = socket(AF_INET,SOCK_STREAM,0);

        sockaddr_in server;
        socklen_t len=sizeof(server);

        server.sin_family=AF_INET;
        server.sin_port=htons(_serPort);
        inet_aton(_serIp.c_str(),&server.sin_addr);


        if(connect(_sock,(const sockaddr*)&server,len) == -1)
        {
            cout<<"error connet"<<endl;
            exit(1);
        }
        cout<<"connet sucess"<<endl;


    }

    ~TcpClient()
    {
        close(_sock);
    }
private:
    int _sock; //套接字
    string _serIp; // 服务器ip
    uint16_t _serPort; //服务器端口

};

多线程版本的大小写字母转换服务

server.hpp

class TcpSever;

struct Data
{
    Data(int sock,const string& ip,uint16_t port,TcpSever* TcpServer_this):_sock(sock),_ip(ip),_port(port),_TcpServer_this(TcpServer_this)
    {}

    int _sock;
    string _ip;
    uint16_t _port;
    TcpSever* _TcpServer_this;
};



class TcpSever
{
public:
    TcpSever(u_int16_t port, string ip = "") : _lisSock(-1), _port(port), _ip(ip)
    {
    }

    void init()
    {
        _lisSock = socket(AF_INET, SOCK_STREAM, 0);

        if (_lisSock == -1)
        {
            cout << "error socket" << endl;
            exit(1);
        }

        cout << "sucess socket" << endl;

        //创建服务器信息
        sockaddr_in server;
        socklen_t len = sizeof(server);
        server.sin_family = AF_INET;
        server.sin_port = htons(_port);

        _ip == "" ? server.sin_addr.s_addr = INADDR_ANY : inet_aton(_ip.c_str(), &server.sin_addr);

        //绑定服务器
        if (bind(_lisSock, (const sockaddr *)&server, len) == -1)
        {
            cout << "error bind" << endl;
            exit(1);

        }
        cout << "sucess bind" << endl;


        // 线程池的创建
        _tp=threadPool<Task>::getinstance();
    }

    void load()
    {
        //监听_sock
        if (listen(_lisSock, 5) == -1)
        {
            cout << "error listen" << endl;
            exit(1);

        }
        cout << "sucess listen" << endl;

        while (1)
        {
            sockaddr_in client;
            socklen_t len = sizeof(client);

            int sock = accept(_lisSock, (sockaddr *)&client, &len);
            if (sock == -1)
            {
                cout << "error sock" << endl;
                exit(1);

            }
            cout << "succes sock" << endl;

            string client_ip = inet_ntoa(client.sin_addr);
            u_int16_t client_port = ntohs(client.sin_port);


            // 多线程版本
            Data d(sock,client_ip,client_port,this);
            pthread_t tid;
            pthread_create(&tid,nullptr,Routine,&d);


    }
    static void* Routine(void* args)
    {
        Data* pd = (Data*) args;

        pd->_TcpServer_this->LotoUp(pd->_sock,pd->_ip,pd->_port);
    }

    //翻译大小写
    void LotoUp(int sock, string ip, u_int16_t port)
    {
        cout<<"sucess LotoUp"<<endl;
        while (1)
        {

            char inbuf[1024];
            ssize_t s = read(sock, inbuf, 1024);
            if (s > 0)
            {
                inbuf[s]='\0';
                cout<<"before:"<<inbuf<<endl;
                for (int i = 0; i < s; i++)
                {
                    inbuf[i] = toupper(inbuf[i]);
                }

                cout<<"after:"<<inbuf<<endl;

                write(sock, inbuf, s);
                cout << ip << ":" << port << "   sucess LotoUp" << endl;
            }
            else if (s == 0)
            {
                cout << ip << ":" << port << "   quit LotoUp" << endl;
                break;
            }
            else
            {
                cout << ip << ":" << port << "   error LotoUp" << endl;
                break;
            }
        }

        close(sock);
    }



    ~TcpSever()
    {
    }

private:
    int _lisSock;    // 监听套接字
    string _ip;      // 服务器ip
    u_int16_t _port; // 服务器端口
};

int main()
{
    TcpSever server(8081);
    server.init();
    server.load();

    return 0;
}

client.hpp


class TcpClient
{
    public:
    TcpClient(string serIp,uint16_t serPort):_serIp(serIp),_serPort(serPort)
    {}
    void start()
    {
        //套接字
        int _sock = socket(AF_INET,SOCK_STREAM,0);

        sockaddr_in server;
        socklen_t len=sizeof(server);

        server.sin_family=AF_INET;
        server.sin_port=htons(_serPort);
        inet_aton(_serIp.c_str(),&server.sin_addr);


        if(connect(_sock,(const sockaddr*)&server,len) == -1)
        {
            cout<<"error connet"<<endl;
            exit(1);
        }
        cout<<"connet sucess"<<endl;
        bool quit=false;
        while(!quit)
        {   
            string outbuf;
            outbuf.clear();
            cout<<"请输入内容>>>";
            getline(cin,outbuf);

            if(outbuf == "quit")
            {
                quit=true;
            }

            ssize_t s = write(_sock,outbuf.c_str(),outbuf.size());

            if(s>0)
            {
                char inbuf[1024];
                ssize_t rs = read(_sock,inbuf,sizeof(inbuf));
                inbuf[rs]=0;
                cout<<inbuf<<endl;
            }

        }

    }

    ~TcpClient()
    {
        close(_sock);
    }
private:
    int _sock; //套接字
    string _serIp; // 服务器ip
    uint16_t _serPort; //服务器端口

};

int main()
{
    TcpClient client("127.0.0.1",8081);
    client.start();

    return 0;
}

效果
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值