网络编程套接字

发布时间:2024年01月22日

预备知识

端口号和进程ID

UDP和TCP

网络字节序

socket编程UDP

常用接口

struct sockaddr_in {
    short            sin_family;   // 地址族,对于IPv4,它是 AF_INET
    unsigned short   sin_port;     // 端口号(使用网络字节序)
    struct in_addr   sin_addr;     // IPv4地址
    char             sin_zero[8];  // 填充0以使结构体与struct sockaddr的大小相同
};

  • command 是要执行的命令的字符串。
  • type 是一个字符串,指定是读取命令的输出(使用 "r")还是向命令写入输入(使用 "w")。

popen 返回一个 FILE * 指针,可以像处理任何其他文件流一样来处理它。如果 popen 调用失败,它将返回 NULL

udp服务器

#include "udpServer.hpp"
#include <memory>

using namespace std;
using namespace Server;

static void Usage(string proc)
{
    cout << "\nUsage:\n\t" << proc << " local_port\n\n";
}

void handlerMessage(string clientip, uint16_t clientport, string message)
{
    
}

// ./udpServer port
int main(int argc, char *argv[])
{
    if(argc != 2)
    {
        Usage(argv[0]);
        exit(USAGE_ERR);
    }
    uint16_t port = atoi(argv[1]);
    // string ip = argv[1];

    std::unique_ptr<udpServer> usvr(new udpServer(handlerMessage, port));

    usvr->initServer();
    usvr->start();

    return 0;
}
#pragma once
#include<string>
#include<iostream>
#include<sys/socket.h>
#include<strings.h>
#include<cerrno>
#include<cstring>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<functional>

static const std::string defalutIp="0.0.0.0";
static const int gnum=1024;

enum{
    USAGE_ERR=1,
    SOCKET_ERR,
    BIND_ERR,
    OPEN_ERR
};

typedef std::function<void(int,std::string,uint16_t,std::string)> func_t;

class udpServer{
public:
    udpServer(const func_t &cb,uint16_t &port,const std::string ip=defalutIp):
    _callback(cb),_port(port),_ip(ip),_sockfd(-1){}

    void initServer(){
        //1.创建socket
        _sockfd=socket(AF_INET,SOCK_DGRAM,0);
        if(_sockfd==-1){
            std::cerr<<"socket error"<<errno<<":"<<strerror(errno)<<std::endl;
            exit(SOCKET_ERR);
        }
        std::cout<<"socket sucess"<<":"<<_sockfd<<std::endl;
        //2.绑定port ip
        struct sockaddr_in local;
        bzero(&local,sizeof(local));
        local.sin_family=AF_INET;
        local.sin_port=htons(_port);
        local.sin_addr.s_addr=INADDR_ANY;
        int n=bind(_sockfd,(struct sockaddr*)&local,sizeof(local));
        if(n==-1){
            std::cerr<<"bind error"<<errno<<":"<<strerror(errno)<<std::endl;
            exit(BIND_ERR);
        }
    }

    void start(){
        char buffer[gnum];
        for(;;){
            //读取数据
            struct sockaddr_in peer;
            socklen_t len=sizeof(peer);
            ssize_t s=recvfrom(_sockfd,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&len);
            if(s>0){
                buffer[s]=0;
                std::string clientip=inet_ntoa(peer.sin_addr);
                uint16_t clientport=ntohs(peer.sin_port);
                std::string message=buffer;

                std::cout<<clientip<<"["<<clientport<<"]#"<<message<<std::endl;
                //对数据处理
                _callback(_sockfd,clientip,clientport,message);
            }
        }
    }

    ~udpServer(){

    }

private:
    uint16_t _port;
    std::string _ip;
    int _sockfd;
    func_t _callback;
};

#pragma once
#include<string>
#include<iostream>
#include<sys/socket.h>
#include<strings.h>
#include<cerrno>
#include<cstring>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>

class udpClient{

public:
    udpClient(const std::string&serverip,const uint16_t &serverport):
    _serverip(serverip),_serverport(serverport),_sockfd(-1),_quit(false){}

    void initClient(){
        //创建socket
        _sockfd=socket(AF_INET,SOCK_DGRAM,0);
        if(_sockfd==-1){
            std::cerr<<"socket error:"<<errno<<":"<<strerror(errno)<<std::endl;
            exit(2);
        }
        std::cout<<"socket sucess:"<<":"<<_sockfd<<std::endl;
    }

    void run(){
        struct sockaddr_in server;
        memset(&server,0,sizeof(server));
        server.sin_family=AF_INET;
        server.sin_addr.s_addr=inet_addr(_serverip.c_str());
        server.sin_port=htons(_serverport);

        std::string message;
        while(!_quit){
            std::cout<<"Please Enter#"<<std::endl;
            std::cin>>message;

            sendto(_sockfd,message.c_str(),message.size(),0,
            (struct sockaddr*)&server,sizeof(server));
        }
    }

    ~udpClient(){

    }
private:
    int _sockfd;
    std::string _serverip;
    uint16_t _serverport;
    bool _quit;
};

汉译英词典

#include"udpServer.hpp"
#include<memory>
#include<fstream>
#include<signal.h>
#include<unordered_map>

using namespace std;
const string dicTxt="./dict.txt";
unordered_map<string,string>dict;

static void Usage(string proc){
    cout<<"\nUsage:\n\t"<<proc<<"local_port\n\n";
}

static bool cutString(const string &target,string *s1,string *s2,const string &sep){
    //apple:苹果
    auto pos=target.find(sep);
    if(pos==string::npos)
        return false;
    *s1=target.substr(0,pos);
    *s2=target.substr(pos+sep.size());
    return true;
}

static void initDict(){
    ifstream in(dicTxt,ios::binary);
    if(in.is_open()){
        cerr<<"open file"<<dicTxt<<"error"<<endl;
        exit(OPEN_ERR);
    }
    string line;
    string key,value;
    while(getline(in,line)){
        if(cutString(line,&key,&value,":")){
            dict.insert(make_pair(key,value));
        }
    }
    in.close();
    cout<<"load dict sucess"<<endl;
}

void reload(int signo){
    (void)signo;
    initDict();
}

static void debugPrint(){
    for(auto &dt:dict){
        cout<<dt.first<<"#"<<dt.second<<endl;
    }
}

void handlerMessage(int sockfd,string clientip, uint16_t clientport, string message)
{
   string response_message;
   auto iter=dict.find(message);
   if(iter==dict.end())
        response_message="unknown";
    else
        response_message=iter->second;
    //开始返回
    struct sockaddr_in client;
    bzero(&client,sizeof(client));

    client.sin_family=AF_INET;
    client.sin_port=htons(clientport);
    client.sin_addr.s_addr=inet_addr(clientip.c_str());

    sendto(sockfd,response_message.c_str(),response_message.size(),0,(struct sockaddr*)&client,
    sizeof(client));

}


int main(int argc,char* argv[]){
    if(argc!=2){
        Usage(argv[0]);
        exit(USAGE_ERR);
    }
    uint16_t port=atoi(argv[1]);
    //string ip=argv[1];

    unique_ptr<udpServer> usvr(new udpServer(handlerMessage,port));
    usvr->initServer();
    usvr->start();
    return 0;
}

模拟shell脚本

void execCommand(int sockfd, string clientip, uint16_t clientport, string cmd)
// {
    //1. cmd解析,ls -a -l
//     //2. 如果必要,可能需要fork, exec*

//     if(cmd.find("rm") != string::npos || cmd.find("mv") != string::npos || cmd.find("rmdir") != string::npos)
//     {
//         cerr << clientip << ":" << clientport << " 正在做一个非法的操作: " << cmd << endl;
//         return;
//     }

//     string response;
//     FILE *fp = popen(cmd.c_str(), "r");
//     if(fp == nullptr) response = cmd + " exec failed";
//     char line[1024];
//     while(fgets(line, sizeof(line), fp))
//     {
//         response += line;
//     }
//     pclose(fp);

//     // 开始返回
//     struct sockaddr_in client;
//     bzero(&client, sizeof(client));

//     client.sin_family = AF_INET;
//     client.sin_port = htons(clientport);
//     client.sin_addr.s_addr = inet_addr(clientip.c_str());

//     sendto(sockfd, response.c_str(), response.size(), 0, (struct sockaddr*)&client, sizeof(client));
// }

socket编程TCP

常用接口

int listen(int sockfd, int backlog);
  • sockfd: 这是之前已经创建并绑定到某个本地地址的 socket 的文件描述符。
  • backlog: 这个参数指定了允许排队等待接受的传入连接请求的最大数量。换句话说,它定义了连接请求的队列长度。

?

  • sockfd: 这是一个监听 socket 的文件描述符,之前已经通过 bindlisten 函数设置为监听模式。
  • addr: 这是一个指向 sockaddr 结构的指针,用于接收远程主机的地址信息(即客户端的地址信息)。
  • addrlen: 这是一个指向 socklen_t 变量的指针,该变量在调用时包含了 addr 所指向的地址结构的大小,调用返回时则包含了实际地址结构的大小。



TCP服务器

tcpClient.hpp

#pragma once
#include<iostream>
#include<cstring>
#include<string>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>

#define NUM 1024

class TcpClient{
public:
    TcpClient(const std::string &serverip,const uint16_t &serverport):
    _sock(-1),_serverip(serverip),_serverport(serverport){}

    void initClient(){
        //1.创建socket
        _sock=socket(AF_INET,SOCK_STREAM,0);
        if(_sock<0){
            std::cerr<<"sock create error"<<std::endl;
            exit(2);
        }
    }

    void start(){
        struct sockaddr_in server;
        memset(&server,0,sizeof(server));
        server.sin_family=AF_INET;
        server.sin_port=htons(_serverport);
        server.sin_addr.s_addr=inet_addr(_serverip.c_str());

        if(connect(_sock,(struct sockaddr*)&server,sizeof(server))!=0){
            std::cerr<<"socket connect error"<<std::endl;
            perror("Connect failed");
            exit(3);
        }
        else{
            std::string msg;
            while(true){
                std::cout<<"Enter#";
                std::getline(std::cin,msg);
                write(_sock,msg.c_str(),msg.size());
                char buffer[NUM]{};
                int n=read(_sock,buffer,sizeof(buffer)-1);
                if(n>0){
                    buffer[n]=0;
                    std::cout<<"Server回显#"<<buffer<<std::endl;
                }
                else{
                    break;
                }
            }
        }
    }
    
    ~TcpClient(){
        if(_sock>=0)
            close(_sock);
    }
private:
    int _sock;
    std::string _serverip;
    uint16_t _serverport;
};

tcpClient.cc

#include"tcpClient.hpp"
#include<memory>

using namespace std;

static void Usage(string proc){
    cout<<"\nUsage:\n\t"<<proc<<"serverip serverport\n\n";
}

int main(int argc,char* argv[]){
    if(argc!=3){
        Usage(argv[0]);
        exit(1);
    }
    string serverip=argv[1];
    uint16_t serverport=atoi(argv[2]);

    unique_ptr<TcpClient> tcli(new TcpClient(serverip,serverport));
    tcli->initClient();
    tcli->start();
    return 0;
}

tcpServer.hpp

#pragma once

#include<iostream>
#include<string>
#include<cstring>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/wait.h>
#include<signal.h>
#include<pthread.h>
#include"log.hpp"

enum{
    USAGE_ERR=1,
    SOCKET_ERR,
    BIND_ERR,
    LISTEN_ERR 
};

static const uint16_t gport=8080;
static const int gbacklog=5;

class TcpServer{
public:
    TcpServer(const uint16_t &port=gport):_listensock(-1),_port(gport){}

    void initServer(){
        //1.创建socket套接字
        _listensock=socket(AF_INET,SOCK_STREAM,0);
        if(_listensock<0){
            logMessgae(FATAL,"create socket error");
            exit(SOCKET_ERR);
        }
        logMessgae(NORMAL,"create socket sucess");
        //2.bind绑定自己的网络信息
        struct sockaddr_in local;
        memset(&local,0,sizeof(local));
        local.sin_family=AF_INET;
        local.sin_port=htons(_port);
        local.sin_addr.s_addr=INADDR_ANY;
        if(bind(_listensock,(struct sockaddr*)&local,sizeof(local))<0){
            logMessgae(FATAL,"bind socket error");
            exit(BIND_ERR);
        }
        logMessgae(NORMAL,"bind socket success");
        //3.设置socket为监听状态
        if(listen(_listensock,gbacklog)<0){
            logMessgae(FATAL,"listen socket error");
            exit(LISTEN_ERR);
        }
        logMessgae(NORMAL,"listen socket sucess");
    }
     void start(){
            for(;;){
                //4.server获取新链接
                struct sockaddr_in peer;
                socklen_t len=sizeof(peer);
                int sock=accept(_listensock,(struct sockaddr*)&peer,&len);
                if(sock<0){
                    logMessgae(ERROR,"accept error,next");
                    continue;
                }
                logMessgae(NORMAL,"accept a new link");
                std::cout<<"sock:"<<sock<<std::endl;
                //5.通信sock
                serviceIO(sock);
                close(sock);
            }
        }

        void serviceIO(int sock){
            char buffer[1024]{};
            while(true){
                ssize_t n=read(sock,buffer,sizeof(buffer)-1);
                if(n>0){
                    buffer[n]=0;
                    std::cout<<"rev message"<<std::endl;

                    std::string outbuffer=buffer;
                    outbuffer+="server[echo]";

                    write(sock,outbuffer.c_str(),outbuffer.size());
                }
                else if(n==0){
                    //代表client退出
                    logMessgae(NORMAL,"client quit,me too!");
                    break;
                }
            }
        }
        ~TcpServer(){}
private:
    int _listensock;
    uint16_t _port;
};

tcpServer.cc

#include"tcpServer.hpp"
#include<memory>

using namespace std;

static void Usage(string proc){
    cout<<"\nUsage:\n\t"<<proc<<"local_pro\n\n"<<endl;
}

//./tcpServer local_port
int main(int argc,char *argv[]){
    if(argc!=2){
        Usage(argv[0]);
        exit(USAGE_ERR);
    }
    uint16_t port=atoi(argv[1]);

    unique_ptr<TcpServer>tsvr(new TcpServer(port));

    tsvr->initServer();
    tsvr->start();
}

???????

文章来源:https://blog.csdn.net/b1169909203/article/details/135670448
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。