0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Linux網(wǎng)絡(luò)編程-TCP客戶端如何獲取要連接的服務(wù)端IP?

碼農(nóng)愛學(xué)習(xí) ? 來源:碼農(nóng)愛學(xué)習(xí) ? 作者:碼農(nóng)愛學(xué)習(xí) ? 2022-09-27 08:56 ? 次閱讀

1 問題引出

在進(jìn)行socket通信開發(fā)時(shí),一般會(huì)用到TCP或UDP這兩種傳輸層協(xié)議,UDP(User Datagram Protocol)是一種面向無連接的協(xié)議,在數(shù)據(jù)發(fā)送前,不需要提前建立連接,它可以更高效地傳輸數(shù)據(jù),但可靠性無法保證。TCP(Transmission Control Protocol)是一種面向連接的協(xié)議,一個(gè)應(yīng)用程序開始向另一個(gè)應(yīng)用程序發(fā)送數(shù)據(jù)之前,必須先進(jìn)行握手連接,以保證數(shù)據(jù)的可靠傳輸。所以,對于數(shù)據(jù)可靠性要求較高的場合,一般使用TCP協(xié)議通信。

pYYBAGMxt9uAENTOAACnYIEGgPA680.png

使用TCP方式的socket編程,客戶端需要知道服務(wù)端的IP和端口,然后向服務(wù)端申請連接,對于端口號,可以事先固定一個(gè)特定的端口號,但對于IP地址,在實(shí)際的開發(fā)使用中,比如嵌入式開發(fā)中,兩個(gè)連網(wǎng)的硬件需要進(jìn)行TCP通信,在建立通信,客戶端硬件是不知道服務(wù)端硬件IP的(除了程序開發(fā)階段,事先知道IP,將IP寫死到程序中),因?yàn)橥ǔG闆r下IP是由路由器分配的,不是一個(gè)固定值,這種情況,客戶端如何自動(dòng)獲取服務(wù)端的IP來建立TCP通信呢?

pYYBAGMxt-GAAg1xAAC-1Z78Okw917.png

2 解決方案

本篇就來實(shí)現(xiàn)一種解決方法:在建立TCP通信前,可以先通過UDP通信來獲取服務(wù)端的IP。

UDP具有廣播功能,客戶端可以通過UDP廣播,向局域網(wǎng)內(nèi)的所有設(shè)置發(fā)送廣播包,可以事先定義一種廣播協(xié)議,服務(wù)端在收到特定的廣播包后,判斷為有客戶端需要請求連接,則將自己的IP地址發(fā)送出去,當(dāng)客戶端收到服務(wù)端發(fā)出的IP信息后,即可通過解析到的服務(wù)端IP地址,實(shí)現(xiàn)與服務(wù)端進(jìn)行TCP連接。

poYBAGMxt-aAbWa4AAEoxsgzzzI895.png

3 編程實(shí)現(xiàn)

在進(jìn)行客戶端與服務(wù)端的socket編程之前,先實(shí)現(xiàn)一些兩個(gè)程序都會(huì)用到的功能代碼。

3.1 公共代碼塊

服務(wù)端要將自己的IP發(fā)給客戶端,首先要能自動(dòng)獲取到自己的IP,客戶端在進(jìn)行UDP廣播時(shí),也可以將自己的IP也一起發(fā)出去作為附加信息,所以,需要先實(shí)現(xiàn)一個(gè)獲取自己IP地址的函數(shù):

#define ETH_NAME "wlan0"
//獲取本機(jī)ip(根據(jù)實(shí)際情況修改ETH_NAME)
bool get_local_ip(std::string &ip)
{                                                                                           
    int sock = socket(AF_INET, SOCK_DGRAM, 0); 
    if (sock == -1) 
    {
        printf("[%s] socket err!n", __func__);
        return false;
    }  

    struct ifreq ifr;
    memcpy(&ifr.ifr_name, ETH_NAME, IFNAMSIZ);
    ifr.ifr_name[IFNAMSIZ - 1] = 0;
    if (ioctl(sock, SIOCGIFADDR, &ifr) < 0) 
    {
        printf("[%s] ioctl err!n", __func__);
        return false;
    }   

    struct sockaddr_in sin;
    memcpy(&sin, &ifr.ifr_addr, sizeof(sin));
    ip = std::string(inet_ntoa(sin.sin_addr));
    return true;
}

在進(jìn)行UDP廣播時(shí),客戶端與服務(wù)端需要事先規(guī)定一種信息格式,當(dāng)格式符合時(shí),說明是客戶端要請求IP信息,以及服務(wù)端返回的IP信息,本篇的測試程序,規(guī)定一種比較簡單的方式:

客戶端請求服務(wù)端IP的信息格式為:字符串"new_client_ip"+分隔符“:”+客戶端自己的IP

服務(wù)端回復(fù)自己的IP的信息格式為:字符串"server_ip"+分隔符“:”+服務(wù)端自己的IP

因?yàn)檫@里的信息是字符串,并以冒號分割符來分隔信息段,因此,需要先編寫一個(gè)能拆分字符串的函數(shù):

#define REQUEST_INFO "new_client_ip" //客戶端發(fā)送的廣播信息頭
#define REPLAY_INFO "server_ip" //服務(wù)端回復(fù)的信息頭
#define INFO_SPLIT std::string(":") //信息分割符

//對c字符串按照指定分割符拆分為多個(gè)string字符串
void cstr_split(char *cstr, vector &res, std::string split = INFO_SPLIT)
{        
    res.clear();
    char *token = strtok(cstr, split.c_str());
    while(token)
    {
        res.push_back(std::string(token));
        printf("[%s] token:%sn", __func__, token);
        token = strtok(NULL, split.c_str());
    }
}

//---------使用示例: 解析服務(wù)器的ip----------
char recvbuf[100]={0};
//...接收服務(wù)端返回的信息
vector recvInfo;
cstr_split(recvbuf, recvInfo);
if(recvInfo.size() == 2 && recvInfo[0] == REPLAY_INFO)
{
    std::string serverIP = recvInfo[1];
//...后續(xù)處理

在進(jìn)行UDP廣播前,需要先設(shè)置該套接字為廣播類型,這里將此部分代碼封裝為一個(gè)函數(shù)

//設(shè)置該套接字為廣播類型  
void set_sockopt_broadcast(int socket, bool bEnable = true)
{
    const int opt = (int)bEnable;  
    int nb = setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&opt, sizeof(opt));  
    if(nb == -1)  
    {  
        printf("[%s] set socket errorn", __func__); 
        return;  
    }  
}

3.2 客戶端程序

3.2.1 客戶端進(jìn)行UDP廣播

客戶端進(jìn)行UDP廣播的主要邏輯是:

獲取自己的IP(作為UDP廣播的附加信息)

創(chuàng)建一個(gè)socket,類型為UDP數(shù)據(jù)報(bào)(SOCK_DGRAM)

sockaddrd的IP設(shè)置為廣播IP(INADDR_BROADCAST, 255.255.255.255)

為socket添加廣播屬性(setsockopt,SO_BROADCAST)

發(fā)送UDP廣播報(bào)(sendto)

接收UDP回復(fù)信息(recvfrom),接收設(shè)置超時(shí)時(shí)間(setsockopt,SO_RCVTIMEO),沒收到服務(wù)端回復(fù)則繼續(xù)廣播

收到服務(wù)端回復(fù)后,解析出服務(wù)端的IP地址,然后即可中止廣播

具體代碼實(shí)現(xiàn)如下:

int main()  
{  
    bool bHasGetServerIP = false;
    thread th_tcp_client;

    std::string localIP = "xxx";
    if (true == get_local_ip(localIP))
    {
        printf("[%s] localIP: [%s] %sn", __func__, ETH_NAME, localIP.c_str());
    }
 
    int udpClientSocket = -1;  
    if ((udpClientSocket = socket(AF_INET, SOCK_DGRAM, 0)) == -1)   
    {     
        printf("[%s] socket errorn", __func__);   
        return false;  
    }     
 
    struct sockaddr_in udpClientAddr;  
    memset(&udpClientAddr, 0, sizeof(struct sockaddr_in));  
    udpClientAddr.sin_family=AF_INET;  
    udpClientAddr.sin_addr.s_addr=htonl(INADDR_BROADCAST);  
    udpClientAddr.sin_port=htons(6000);  
    int nlen=sizeof(udpClientAddr);  
    
    set_sockopt_broadcast(udpClientSocket);
 
    while(1)  
    {  
        sleep(1);
        
        if(bHasGetServerIP)
        {
            continue; //獲取到服務(wù)器的IP后, 就不需要再廣播了
        }
        
        //從廣播地址發(fā)送消息  
        std::string smsg = REQUEST_INFO + INFO_SPLIT + localIP;
        int ret=sendto(udpClientSocket, smsg.c_str(), smsg.length(), 0, (sockaddr*)&udpClientAddr, nlen);  
        if(ret<0)  
        {  
            printf("[%s] sendto error, ret: %dn", __func__, ret);  
        }  
        else  
        {         
            printf("[%s] broadcast ok, msg: %sn", __func__, smsg.c_str());  

            /* 設(shè)置阻塞超時(shí) */
            struct timeval timeOut;
            timeOut.tv_sec = 2; //設(shè)置2s超時(shí)
            timeOut.tv_usec = 0;
            if (setsockopt(udpClientSocket, SOL_SOCKET, SO_RCVTIMEO, &timeOut, sizeof(timeOut)) < 0)
            {
                printf("[%s] time out setting failedn", __func__);
                return 0;
            }

            //再接收數(shù)據(jù)
            char recvbuf[100]={0};
            int num = recvfrom(udpClientSocket, recvbuf, 100, 0, (struct sockaddr*)&udpClientAddr,(socklen_t*)&nlen);
            if (num > 0)
            {
                printf("[%s] receive server reply:%sn", __func__, recvbuf);
                //解析服務(wù)器的ip
                vector recvInfo;
                cstr_split(recvbuf, recvInfo);
                if(recvInfo.size() == 2 && recvInfo[0] == REPLAY_INFO)
                {
                    std::string serverIP = recvInfo[1];
                    bHasGetServerIP = true;
                    th_tcp_client = thread(tcp_client_thread, serverIP, localIP);
                    th_tcp_client.join();
                }
            } 
            else if (num == -1 && errno == EAGAIN)
            {
                printf("[%s] receive timeoutn", __func__);
            }
        }  
    }  
 
    return 0;  
}

3.2.2 客戶端進(jìn)行TCP連接

在獲取到服務(wù)端的IP后,再開啟一個(gè)線程,與服務(wù)端建立TCP連接,并進(jìn)行數(shù)據(jù)通信,該線程的實(shí)現(xiàn)邏輯如下:

創(chuàng)建一個(gè)socket,類型為TCP數(shù)據(jù)流(SOCK_STREAM)

sockaddrd的IP設(shè)置為剛才獲取的服務(wù)端的IP(serverIP,例如192.168.1.101)

向服務(wù)端請求連接(connect)

連接成功之后,可以發(fā)送自定義的數(shù)據(jù)(send),這里發(fā)送的一串字母"abcdefg"加上自己的IP地址

如果服務(wù)端會(huì)還會(huì)回復(fù)信息,可以進(jìn)行接收(recv),這里的接收設(shè)置為非阻塞模式(MSG_DONTWAIT),這樣在服務(wù)端沒有回復(fù)數(shù)據(jù)的情況下,客戶端也不會(huì)一直等待,能夠再次發(fā)送自己的數(shù)據(jù)

具體的代碼實(shí)現(xiàn)如下:

void tcp_client_thread(std::string serverIP, std::string localIP)
{
    printf("[%s] in, prepare connect serverIP:%sn", __func__, serverIP.c_str());
    
	//創(chuàng)建客戶端套接字文件
	int tcpClientSocket= socket(AF_INET, SOCK_STREAM, 0);
    
	//初始化服務(wù)器端口地址
    struct sockaddr_in servaddr;
	bzero(&servaddr, sizeof(servaddr)) ;
	servaddr.sin_family= AF_INET;
	inet_pton(AF_INET, serverIP.c_str(), &servaddr.sin_addr);
	servaddr.sin_port= htons(SERV_PORT);
    
	//請求連接
	connect(tcpClientSocket, (struct sockaddr*)&servaddr, sizeof (servaddr));
    
    //要向服務(wù)器發(fā)送的信息
    char buf [MAXLINE];
	std::string msg = "abcdefg" + std::string("(") + localIP + std::string(")");
    while(1)
    {
        //發(fā)送數(shù)據(jù)
        send(tcpClientSocket, msg.c_str(), msg.length(),0);
        printf("[%s] send to server: %sn", __func__, msg.c_str());
        
        //接收服務(wù)器返回的數(shù)據(jù)
        int n= recv(tcpClientSocket, buf, MAXLINE, MSG_DONTWAIT); //非阻塞讀取
        if(n>0)
        {
            printf("[%s] Response from server: %sn", __func__, buf);
        }
        
        sleep(2);
    }
	//關(guān)閉連接
	close(tcpClientSocket) ;
}

3.3 服務(wù)端程序

服務(wù)端程序,主要設(shè)計(jì)了2個(gè)線程來分別實(shí)現(xiàn)對客戶端UDP廣播的處理和對客戶端TCP連接的處理,兩個(gè)功能獨(dú)立開來,可以實(shí)現(xiàn)對多個(gè)客戶端的UDP請求和TCP請求進(jìn)行處理。

int main()  
{  
    thread th1(recv_broadcast_thread);
    thread th2(tcp_server_thread);
    th1.join();
    th2.join();
 
    return 0;  
}

3.3.1 服務(wù)端處理UDP廣播

接收客戶端廣播信息的處理線程的主要邏輯為:

獲取自己的IP(用于回復(fù)給客戶端,客戶端獲取到IP后進(jìn)行TCP連接)

創(chuàng)建一個(gè)socket,類型為UDP數(shù)據(jù)報(bào)(SOCK_DGRAM)

sockaddrd的IP設(shè)置為接收所有IP(INADDR_ANY,0.0.0.0),并進(jìn)行綁定(bind)

為socket添加廣播屬性(setsockopt,SO_BROADCAST)

接收UDP廣播信息(recvfrom),這里是默認(rèn)的阻塞接收,沒有廣播信息則一直等待

收到客戶端的UDP廣播信息后,解析信息,判斷確實(shí)是要獲取IP后,將自己的IP信息按照規(guī)定的格式發(fā)送出去

具體的代碼實(shí)現(xiàn)如下:

//接收客戶端廣播信息的處理線程, 收到客戶端的UDP廣播后, 將自己(服務(wù)端)的IP發(fā)送回去
void recv_broadcast_thread()
{
    std::string localIP = "";
    if (true == get_local_ip(localIP))
    {
        printf("[%s] localIP: [%s] %sn", __func__, ETH_NAME, localIP.c_str());
    }
    else
    {
        printf("[%s] get local ip err!n", __func__);
        return;
    }

    int sock = -1;  
    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)   
    {     
        printf("[%s] socket errorn", __func__); 
        return;  
    }     
 
    struct sockaddr_in udpServerAddr;  
    bzero(&udpServerAddr, sizeof(struct sockaddr_in));  
    udpServerAddr.sin_family = AF_INET;  
    udpServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);  
    udpServerAddr.sin_port = htons(6000);  
    int len = sizeof(sockaddr_in); 
    
    if(bind(sock,(struct sockaddr *)&(udpServerAddr), sizeof(struct sockaddr_in)) == -1)   
    {     
        printf("[%s] bind errorn", __func__);  
        return;  
    }  
    
    set_sockopt_broadcast(sock);
 
    char smsg[100] = {0};  
 
    while(1)  
    {  
        //從廣播地址接收消息  
        int ret=recvfrom(sock, smsg, 100, 0, (struct sockaddr*)&udpServerAddr, (socklen_t*)&len);  
        if(ret<=0)  
        {  
            printf("[%s] read error, ret:%dn", __func__, ret);  
        }  
        else  
        {         
            printf("[%s]receive: %sn", __func__, smsg);
            
            vector recvInfo;
            cstr_split(smsg, recvInfo);
            
            //將自己的IP回應(yīng)給請求的客戶端
            if(recvInfo.size() == 2 && recvInfo[0] == REQUEST_INFO)
            {
                std::string clientIP = recvInfo[1];
                std::string replyInfo = REPLAY_INFO + INFO_SPLIT + localIP;
                
                ret = sendto(sock, replyInfo.c_str(), replyInfo.length(), 0, (struct sockaddr *)&udpServerAddr, len);
                if(ret<0)  
                {  
                    printf("[%s] sendto error, ret: %dn", __func__, ret);  
                }  
                else  
                {         
                    printf("[%s] reply ok, msg: %sn", __func__, replyInfo.c_str());   
                }  
            }
        }  
 
        sleep(1);  
    } 
}

3.3.2 服務(wù)端處理客戶端的TCP連接

TCP服務(wù)器線程, 用于接受客戶端的連接, 主要邏輯如下:

創(chuàng)建一個(gè)socket,命名為listenfd,類型為TCP數(shù)據(jù)流(SOCK_STREAM)

sockaddrd的IP設(shè)置為接收所有IP(INADDR_ANY,0.0.0.0),并進(jìn)行綁定(bind)

監(jiān)聽,并設(shè)置最大連接數(shù)(listen)

創(chuàng)建一個(gè)epoll,來處理多客戶端請求時(shí)(epoll_create)

將TCP socket添加到epoll進(jìn)行監(jiān)聽(epoll_ctl,EPOLLIN)

epoll等待事件到來(epoll_wait)

epoll處理到來的事件

如果到來的是listenfd,說明有新的客戶端請求連接,TCP服務(wù)端則接受請求(accept),然后將對應(yīng)的客戶端fd添加到epoll進(jìn)行監(jiān)聽(epoll_ctl,EPOLLIN)

如果到來的不是listenfd,說明有已連接的客戶端發(fā)來的數(shù)據(jù)信息,則讀取信息(read)

具體的代碼實(shí)現(xiàn)如下:

//TCP服務(wù)器線程, 用于接受客戶端的連接, 并接收客戶端的信息
void tcp_server_thread()
{
	//創(chuàng)建服務(wù)器端套接字文件
	int listenfd=socket(AF_INET, SOCK_STREAM, 0);
    
	//初始化服務(wù)器端口地址
    struct sockaddr_in tcpServerAddr;
	bzero(&tcpServerAddr, sizeof(tcpServerAddr));
	tcpServerAddr.sin_family=AF_INET;
	tcpServerAddr.sin_addr.s_addr= htonl(INADDR_ANY);
	tcpServerAddr.sin_port=htons(SERV_PORT);
    
	//將套接字文件與服務(wù)器端口地址綁定
	bind(listenfd, (struct sockaddr *)&tcpServerAddr, sizeof (tcpServerAddr)) ;
    
	//監(jiān)聽,并設(shè)置最大連接數(shù)為20
	listen(listenfd, 20);
	printf("[%s] Accepting connections... n", __func__);
    
    //通過epoll來監(jiān)控多個(gè)客戶端的請求
    int epollfd;
    struct epoll_event events[EPOLLEVENTS];
    int num;
    char buf[MAXSIZE];
    memset(buf,0,MAXSIZE);
    epollfd = epoll_create(FDSIZE);
    printf("[%s] create epollfd:%dn", __func__, epollfd);

    //添加監(jiān)聽描述符事件
    epoll_set_fd_a_event(epollfd, EPOLL_CTL_ADD, listenfd, EPOLLIN);
    while(1)
    {
        //獲取已經(jīng)準(zhǔn)備好的描述符事件
        printf("[%s] epollfd:%d epoll_wait...n", __func__, epollfd);
        num = epoll_wait(epollfd,events,EPOLLEVENTS,-1);
        for (int i = 0;i < num;i++)
        {
            int fd = events[i].data.fd;
            //listenfd說明有新的客戶端請求連接
            if ((fd == listenfd) &&(events[i].events & EPOLLIN))
            {
                //accept客戶端的請求
                struct sockaddr_in cliaddr;
                socklen_t  cliaddrlen = sizeof(cliaddr);
                int clifd = accept(listenfd,(struct sockaddr*)&cliaddr,&cliaddrlen);
                if (clifd == -1)
                {
                    perror("accpet error:");
                }
                else
                {
                    printf("[%s] accept a new client(fd:%d): %s:%dn",
                           __func__, clifd, inet_ntoa(cliaddr.sin_addr), cliaddr.sin_port);
                    //將客戶端fd添加到epoll進(jìn)行監(jiān)聽
                    epoll_set_fd_a_event(epollfd, EPOLL_CTL_ADD, clifd, EPOLLIN);
                }
            }
            //收到已連接的客戶端fd的消息
            else if (events[i].events & EPOLLIN)
            {
                memset(buf,0,MAXSIZE);
                //讀取客戶端的消息
                int nread = read(fd,buf,MAXSIZE);
                if (nread == -1)
                {
                    perror("read error:");
                    close(fd);
                    epoll_set_fd_a_event(epollfd, EPOLL_CTL_DEL, fd, EPOLLIN);
                }
                else if (nread == 0)
                {
                    printf("[%s] client(fd:%d) close.n", __func__, fd);
                    close(fd);
                    epoll_set_fd_a_event(epollfd, EPOLL_CTL_DEL, fd, EPOLLIN);
                }
                else
                {
                    //將客戶端的消息打印處理, 并表明是哪里客戶端fd發(fā)來的消息
                    printf("[%s] read message from fd:%d ---> %sn", __func__, fd, buf);
                }
            }
        }
    }

    close(epollfd);
}

為epoll中的某個(gè)fd添加、修改或刪除某個(gè)事件,這里封裝成了一個(gè)函數(shù):

//為epoll中的某個(gè)fd添加/修改/刪除某個(gè)事件
bool epoll_set_fd_a_event(int epollfd, int op, int fd, int event)
{
    if (EPOLL_CTL_ADD == op || EPOLL_CTL_MOD == op || EPOLL_CTL_DEL == op)
    {
        struct epoll_event ev;
        ev.events = event;
        ev.data.fd = fd;
        epoll_ctl(epollfd, op, fd, &ev);
        return true;
    }
    else
    {
        printf("[%s] err op:%dn", __func__, op);
        return false;
    }
}

4 測試結(jié)果

這里測試了4種不同的情況,來驗(yàn)證客戶端可以自動(dòng)獲取到服務(wù)端的IP,并進(jìn)行TCP連接,另外,服務(wù)端也可以處理多個(gè)客戶端的請求:

1)單個(gè)客戶端連接服務(wù)端

pYYBAGMxuDyAIwy0AACUY98LKLo152.png

2)單個(gè)客戶端連接并中止后,另一個(gè)客戶端再次連接服務(wù)端

poYBAGMxuECAMtQYAACX36W2fMQ056.png

3)客戶端先啟動(dòng)后,服務(wù)端再啟動(dòng),客戶端依然能在服務(wù)端啟動(dòng)后連接到服務(wù)端

poYBAGMxuEWATxmAAACkHUbg1GU539.png

4)兩個(gè)客戶端現(xiàn)后進(jìn)行連接服務(wù)端

pYYBAGMxuEmAfDWwAADnwMZuH8M509.png

5 總結(jié)

本篇介紹了在TCP通信中,客戶端通過UDP廣播,實(shí)現(xiàn)自動(dòng)獲取服務(wù)端的IP地址,并進(jìn)行TCP連接的具體方法,并通過代碼實(shí)現(xiàn),來測試此方案是實(shí)際效果,為了使服務(wù)端能夠處理多個(gè)客戶端的請求,這里使用了多線程編程,以及epoll機(jī)制來實(shí)現(xiàn)多客戶端的處理。

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11417

    瀏覽量

    212268
  • TCP
    TCP
    +關(guān)注

    關(guān)注

    8

    文章

    1395

    瀏覽量

    80093
  • 網(wǎng)絡(luò)編程
    +關(guān)注

    關(guān)注

    0

    文章

    72

    瀏覽量

    10440
收藏 人收藏

    評論

    相關(guān)推薦

    TCP服務(wù)端測試工具

    本帖最后由 小子個(gè) 于 2024-3-20 22:58 編輯 該TCP服務(wù)端工具可以理解為 “TCP服務(wù)端” 或者 “服務(wù)器” ,
    發(fā)表于 06-29 09:22

    AT模式建立TCP客戶端連接一直不成功是怎么回事?

    =\"TCP\",\"192.168.0.111\",8080 ERROR CLOSED 網(wǎng)絡(luò)調(diào)試助手軟件建立 TCP 服務(wù)端 端口號:8080 如果用8266建立
    發(fā)表于 07-18 06:42

    TCP客戶端和單服務(wù)端之間通信問題

    假如有多個(gè)客戶端同時(shí)連接服務(wù)端,怎么知道是哪個(gè)客戶端傳輸數(shù)據(jù)過來,是有事件還是一個(gè)個(gè)輪詢過去呢
    發(fā)表于 12-22 21:25

    TCP服務(wù)端的實(shí)現(xiàn)

    Swoole TCP服務(wù)端客戶端 持續(xù)更新
    發(fā)表于 09-26 16:04

    TCP通信時(shí)服務(wù)端如何接收客戶端的數(shù)據(jù)?

    畢設(shè)采用的是TCP協(xié)議,組員做的是下位機(jī),C編程,WiFi模塊工作處于客戶端。我負(fù)責(zé)上位機(jī),Labview使用tcp協(xié)議時(shí)服務(wù)端怎么接收
    發(fā)表于 04-14 14:49

    LabVIEW 做TCP服務(wù)端怎么把多個(gè)客戶端區(qū)分開

    LabVIEW 做TCP服務(wù)端因?yàn)?b class='flag-5'>要連接四個(gè)客戶端假如有四個(gè)客戶端分別是1號 2號 3號 4號,
    發(fā)表于 05-29 16:48

    4412開發(fā)板Qt網(wǎng)絡(luò)編程-TCP實(shí)現(xiàn)服務(wù)器和客戶端

    網(wǎng)絡(luò)編程TCP 和 UDP,TCP 編程需要用到倆個(gè)類:QTcpServer 和 QTcpSocket。1
    發(fā)表于 04-28 15:33

    監(jiān)控系統(tǒng)客戶端服務(wù)端設(shè)計(jì)

    詳情2.1.2 數(shù)據(jù)庫接口及實(shí)現(xiàn)2.1.2.1 用戶注冊2.1.2.2 用戶查詢2.2 監(jiān)控系統(tǒng)客戶端服務(wù)端設(shè)計(jì)2.2.1 `CS`模型2.2.2 功能2.2.2 服務(wù)機(jī)與客戶機(jī)交互
    發(fā)表于 12-21 07:02

    CH395作為TCP客戶端,連接電腦TCP服務(wù)端的時(shí)間很長怎么解決?

    CH395作為TCP客戶端,電腦作為TCP服務(wù)端,第一次連接時(shí)很快就能連接上只需1秒。
    發(fā)表于 10-14 06:09

    Android 仿QQ客戶端服務(wù)端源碼

    Android 仿QQ客戶端服務(wù)端源碼
    發(fā)表于 03-19 11:23 ?3次下載

    Linux網(wǎng)絡(luò)編程TCP并發(fā)服務(wù)器和TCP客戶端程序免費(fèi)下載

    本文檔的主要內(nèi)容詳細(xì)介紹的是Linux網(wǎng)絡(luò)編程TCP并發(fā)服務(wù)器和TCP
    發(fā)表于 01-08 15:12 ?9次下載
    <b class='flag-5'>Linux</b>下<b class='flag-5'>網(wǎng)絡(luò)</b><b class='flag-5'>編程</b><b class='flag-5'>TCP</b>并發(fā)<b class='flag-5'>服務(wù)</b>器和<b class='flag-5'>TCP</b><b class='flag-5'>客戶端</b>程序免費(fèi)下載

    LinuxTCP網(wǎng)絡(luò)編程-創(chuàng)建服務(wù)器與客戶端

    這篇文章介紹在Linux下的socket編程,完成TCP服務(wù)器、客戶端的創(chuàng)建,實(shí)現(xiàn)數(shù)據(jù)通信。
    的頭像 發(fā)表于 08-14 09:26 ?2688次閱讀
    <b class='flag-5'>Linux</b>下<b class='flag-5'>TCP</b><b class='flag-5'>網(wǎng)絡(luò)</b><b class='flag-5'>編程</b>-創(chuàng)建<b class='flag-5'>服務(wù)</b>器與<b class='flag-5'>客戶端</b>

    MQTT中服務(wù)端客戶端

    MQTT 是一種基于客戶端-服務(wù)端架構(gòu)(C/S)的消息傳輸協(xié)議,所以在 MQTT 協(xié)議通信中,有兩個(gè)最為重要的角色,它們便是服務(wù)端客戶端。 1)
    的頭像 發(fā)表于 07-30 14:55 ?2979次閱讀

    服務(wù)端如何控制客戶端之間的信息通訊

    進(jìn)行管理。 比如上圖所示,假設(shè)我們需要利用手機(jī)和電腦獲取開發(fā)板在運(yùn)行過程中 SoC 芯片的溫度,那么首先電腦和手機(jī)這兩個(gè)客戶端需要向 MQTT服務(wù)器訂閱主題“芯片溫度”;接下來,當(dāng)開發(fā)板客戶端
    的頭像 發(fā)表于 07-30 15:10 ?992次閱讀
    <b class='flag-5'>服務(wù)端</b>如何控制<b class='flag-5'>客戶端</b>之間的信息通訊

    服務(wù)端測試和客戶端測試區(qū)別在哪

    服務(wù)端測試和客戶端測試是軟件開發(fā)過程中的兩個(gè)重要環(huán)節(jié),它們分別針對服務(wù)器端客戶端的軟件進(jìn)行測試。本文將詳細(xì)介紹服務(wù)端測試和
    的頭像 發(fā)表于 05-30 15:27 ?4122次閱讀

    電子發(fā)燒友

    中國電子工程師最喜歡的網(wǎng)站

    • 2931785位工程師會(huì)員交流學(xué)習(xí)
    • 獲取您個(gè)性化的科技前沿技術(shù)信息
    • 參加活動(dòng)獲取豐厚的禮品