网络编程套接字

预备知识

端口号和进程ID

网络编程套接字_第1张图片

网络编程套接字_第2张图片网络编程套接字_第3张图片

UDP和TCP

网络编程套接字_第4张图片

网络编程套接字_第5张图片

网络字节序

网络编程套接字_第6张图片

网络编程套接字_第7张图片

socket编程UDP

常用接口

网络编程套接字_第8张图片

网络编程套接字_第9张图片

网络编程套接字_第10张图片

网络编程套接字_第11张图片

网络编程套接字_第12张图片

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的大小相同
};

网络编程套接字_第13张图片

网络编程套接字_第14张图片

网络编程套接字_第15张图片

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

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

udp服务器

#include "udpServer.hpp"
#include 

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 usvr(new udpServer(handlerMessage, port));

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

    return 0;
}
#pragma once
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

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 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"<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<

#pragma once
#include
#include
#include
#include
#include
#include
#include
#include
#include

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:"<>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
#include
#include
#include

using namespace std;
const string dicTxt="./dict.txt";
unordered_mapdict;

static void Usage(string proc){
    cout<<"\nUsage:\n\t"<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 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

常用接口

网络编程套接字_第16张图片

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

网络编程套接字_第17张图片

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

网络编程套接字_第18张图片

TCP服务器

tcpClient.hpp

#pragma once
#include
#include
#include
#include
#include
#include
#include
#include

#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"<0){
                    buffer[n]=0;
                    std::cout<<"Server回显#"<=0)
            close(_sock);
    }
private:
    int _sock;
    std::string _serverip;
    uint16_t _serverport;
};

tcpClient.cc

#include"tcpClient.hpp"
#include

using namespace std;

static void Usage(string proc){
    cout<<"\nUsage:\n\t"< tcli(new TcpClient(serverip,serverport));
    tcli->initClient();
    tcli->start();
    return 0;
}

tcpServer.hpp

#pragma once

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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:"<0){
                    buffer[n]=0;
                    std::cout<<"rev message"<

tcpServer.cc

#include"tcpServer.hpp"
#include

using namespace std;

static void Usage(string proc){
    cout<<"\nUsage:\n\t"<tsvr(new TcpServer(port));

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

TCP三次握手和四次挥手

网络编程套接字_第19张图片

三次握手过程如下:

  1. SYN(同步):在三次握手的第一步中,客户端发送一个SYN(同步)标志的数据包到服务器,以表示它想要建立连接。这个数据包包含一个客户端的初始序列号(ISN),这是用于TCP数据传输的一个关键参数。

  2. SYN-ACK(同步-确认):服务器收到客户端的SYN包后,会发送一个SYN-ACK包作为回应。这个数据包包含服务器自己的初始序列号,以及对客户端初始序列号的确认(客户端的ISN+1)。

  3. ACK(确认):在接收到服务器的SYN-ACK包后,客户端发送一个ACK包给服务器。这个ACK包包含对服务器初始序列号的确认(服务器的ISN+1)。

完成这三步之后,TCP连接就建立了,数据可以在客户端和服务器之间传输。这个过程的目的是同步双方的序列号和确认号,确保双方都准备好接收和发送数据,防止数据丢失或者重复。

四次挥手过程如下:

  1. 客户端发送FIN:当客户端完成数据传输并准备关闭连接时,它会发送一个FIN(结束)标志的数据包给服务器。这表示客户端没有更多的数据要发送,但它仍然可以接收数据。

  2. 服务器ACK客户端的FIN:服务器接收到客户端的FIN后,会回复一个ACK(确认)标志的数据包。这个ACK包是对客户端的FIN包的确认。此时,客户端到服务器的连接被关闭,但服务器到客户端的连接仍然开放,直到服务器准备好关闭连接。

  3. 服务器发送FIN:当服务器也完成了数据传输并准备关闭连接时,它会发送一个FIN标志的数据包给客户端。

  4. 客户端ACK服务器的FIN:客户端接收到服务器的FIN后,会回复一个ACK标志的数据包,确认收到了服务器的FIN包。在发送这个ACK包之后,客户端会进入一个名为TIME_WAIT的状态,持续等待足够的时间以确保服务器接收到了它的ACK包

网络编程套接字_第20张图片

网络编程套接字_第21张图片

你可能感兴趣的:(服务器)