欧美vvv,亚洲第一成人在线,亚洲成人欧美日韩在线观看,日本猛少妇猛色XXXXX猛叫

新聞資訊

    說到 web 服務器想必大多數(shù)人首先想到的協(xié)議是 http,那么 http 之下則是 tcp,本篇文章將通過 tcp 來實現(xiàn)一個簡單的 web 服務器。

    本篇文章將著重講解如何實現(xiàn),對于 http 與 tcp 的概念本篇將不過多講解。

    一、了解 Socket 及 web 服務工作原理

    既然是基于 tcp 實現(xiàn) web 服務器,很多學習 C 語言的小伙伴可能會很快的想到套接字 socket。socket 是一個較為抽象的通信進程,或者說是主機與主機進行信息交互的一種抽象。socket 可以將數(shù)據(jù)流送入網(wǎng)絡中,也可以接收數(shù)據(jù)流。

    socket 的信息交互與本地文件信息的讀取從表面特征上看類似,但其中所存在的編寫復雜度是本地 IO 不能比擬的,但卻有相似點。在 win 下 socket 的交互交互步驟為:WSAStartup 進行初始化--> socket 創(chuàng)建套接字--> bind 綁定--> listen 監(jiān)聽--> connect 連接--> accept 接收請求--> send/recv 發(fā)送或接收數(shù)據(jù)--> closesocket 關閉 socket--> WSACleanup 最終關閉。

    了解完了一個 socket 的基本步驟后我們了解一下一個基本 web 請求的用戶常規(guī)操作,操作分為:打開瀏覽器-->輸入資源地址 ip 地址-->得到資源。當目標服務器接收到該操作產(chǎn)生掉請求后,我們可以把服務器的響應流程步驟看為:獲得 request 請求-->得到請求關鍵數(shù)據(jù)-->獲取關鍵數(shù)據(jù)-->發(fā)送關鍵數(shù)據(jù)。服務器的這一步流程是在啟動socket 進行監(jiān)聽后才能響應。通過監(jiān)聽得知接收到請求,使用 recv 接收請求數(shù)據(jù),從而根據(jù)該參數(shù)得到進行資源獲取,最后通過 send 將數(shù)據(jù)進行返回。

    二、創(chuàng)建sokect完成監(jiān)聽

    2.1 WSAStartup初始化

    首先在c語言頭文件中引入依賴 WinSock2.h:

    #include <WinSock2.h>
    

    在第一點中對 socket 的創(chuàng)建步驟已有說明,首先需要完成 socket 的初始化操作,使用函數(shù) WSAStartup,該函數(shù)的原型為:

    int WSAStartup(
      WORD      wVersionRequired,
      LPWSADATA lpWSAData
    );
    

    該函數(shù)的參數(shù) wVersionRequired 表示 WinSock2 的版本號;lpWSAData 參數(shù)為指向 WSADATA 的指針,WSADATA 結構用于 WSAStartup 初始化后返回的信息。

    wVersionRequired 可以使用 MAKEWORD 生成,在這里可以使用版本 1.1 或版本2.2,1.1 只支持 TCP/IP,版本 2.1 則會有更多的支持,在此我們選擇版本 1.1。

    首先聲明一個 WSADATA 結構體 :

    WSADATA wsaData;
    

    隨后傳參至初始化函數(shù) WSAStartup 完成初始化:

    WSAStartup(MAKEWORD(1, 1), &wsaData)
    

    WSAStartup 若初始化失敗則會返回非0值:

    if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) 
    {
     exit(1);
    }
    

    2.2 創(chuàng)建socket 套接字

    初始化完畢后開始創(chuàng)建套接字,套接字創(chuàng)建使用函數(shù),函數(shù)原型為:

    SOCKET WSAAPI socket(
      int af,
      int type,
      int protocol
    );
    

    在函數(shù)原型中,af 表示 IP 地址類型,使用 PF_INET 表示 IPV4,type 表示使用哪種通信類型,例如 SOCK_STREAM 表示 TCP,protocol 表示傳輸協(xié)議,使用 0 會根據(jù)前 2 個參數(shù)使用默認值。

    int skt = socket(PF_INET, SOCK_STREAM, 0);
    

    創(chuàng)建完 socket 后,若為 -1 表示創(chuàng)建失敗,進行判斷如下:

    if (skt == -1) 
    {         
     return -1;
    }
    

    2.3 綁定服務器

    創(chuàng)建完 socket 后需要對服務器進行綁定,配置端口信息、IP 地址等。 首先查看 bind 函數(shù)需要哪一些參數(shù),函數(shù)原型如下:

    int bind(
      SOCKET         socket,
      const sockaddr *addr,
      int            addrlen
    );
    

    參數(shù) socket 表示綁定的 socket,傳入 socket 即可;addr 為 sockaddr_in 的結構體變量的指針,在 sockaddr_in 結構體變量中配置一些服務器信息;addrlen 為 addr 的大小值。

    通過 bind 函數(shù)原型得知了我們所需要的數(shù)據(jù),接下來創(chuàng)建一個 sockaddr_in 結構體變量用于配置服務器信息:

    struct sockaddr_in server_addr;
    

    隨后配置地址家族為AF_INET對應TCP/IP:

    server_addr.sin_family = AF_INET;
    

    接著配置端口信息:

    server_addr.sin_port = htons(8080);
    

    再指定 ip 地址:

    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    

    ip 地址若不確定可以手動輸入,最后使用神器 memset 初始化內(nèi)存,完整代碼如下:

    //配置服務器 
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(8080);
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    memset(&(server_addr.sin_zero), '\0', 8);
    

    隨后使用 bind 函數(shù)進行綁定且進行判斷是否綁定成功:

    //綁定
    if (bind(skt, (struct sockaddr *)&server_addr,sizeof(server_addr)) == -1) {       
     return -1; 
    } 
    

    2.4 listen進行監(jiān)聽

    綁定成功后開始對端口進行監(jiān)聽。查看 listen 函數(shù)原型:

    int listen(
     int sockfd, 
     int backlog
    )
    

    函數(shù)原型中,參數(shù) sockfd 表示監(jiān)聽的套接字,backlog 為設置內(nèi)核中的某一些處理(此處不進行深入講解),直接設置成 10 即可,最大上限為 128。使用監(jiān)聽并且判斷是否成功代碼為:

    if (listen(skt, 10) == -1 ) {    
     return -1;
    }
    

    此階段完整代碼如下:

    #include <WinSock2.h>
    #include<stdio.h> 
    int main(){
     //初始化 
     WSADATA wsaData;
     if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) {
      exit(1);
     }
     //socket創(chuàng)建 
     int skt = socket(PF_INET, SOCK_STREAM, 0);
     if (skt == -1) {         
      return -1;
     }
     //配置服務器 
     struct sockaddr_in server_addr;
     server_addr.sin_family = AF_INET;
     server_addr.sin_port = htons(8080);
     server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
     memset(&(server_addr.sin_zero), '\0', 8);
     //綁定
     if (bind(skt, (struct sockaddr *)&server_addr,sizeof(server_addr)) == -1){       
      return -1; 
     } 
     //監(jiān)聽 
     if (listen(skt, 10) == -1 ) {    
      return -1;
     }
     
     printf("Listening ... ...\n");
    }
    

    運行代碼可得知代碼無錯誤,并且輸出 listening:

    2.5 獲取請求

    監(jiān)聽完成后開始獲取請求。受限需要使用 accept 對套接字進行連接,accept 函數(shù)原型如下:

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

    參數(shù) sockfd 為指定的套接字;addr 為指向 struct sockaddr 的指針,一般為客戶端地址;addrlen 一般設置為設置為 sizeof(struct sockaddr_in) 即可。代碼為:

    struct sockaddr_in c_skt; 
    int s_size=sizeof(struct   sockaddr_in);
    int access_skt = accept(skt, (struct sockaddr *)&c_skt, &s_size);
    

    接下來開始接受客戶端的請求,使用recv函數(shù),函數(shù)原型為:

    ssize_t recv(
     int sockfd, 
     void *buf, 
     size_t len, 
     int flags
    )
    

    參數(shù) sockfd 為 accept 建立的通信;buf 為緩存,數(shù)據(jù)存放的位置;len 為緩存大小;flags 一般設置為0即可:

    //獲取數(shù)據(jù) 
    char buf[1024];
    if (recv(access_skt, buf, 1024, 0) == -1) {
     exit(1);
    }
    

    此時我們再到 accpt 和 recv 外層添加一個循環(huán),使之流程可重復:

    while(1){
      //建立連接 
      printf("Listening ... ...\n");
      struct sockaddr_in c_skt; 
      int s_size=sizeof(struct   sockaddr_in);
      int access_skt = accept(skt, (struct sockaddr *)&c_skt, &s_size);
      
      //獲取數(shù)據(jù) 
      char buf[1024];
      if (recv(access_skt, buf, 1024, 0) == -1) {
       exit(1);
      }
     } 
    

    并且可以在瀏覽器輸入 127.0.0.1:8080 將會看到客戶端打印了 listening 新建了鏈接:

    我們添加printf語句可查看客戶端請求:

    while(1){
      //建立連接 
      printf("Listening ... ...\n");
      struct sockaddr_in c_skt; 
      int s_size=sizeof(struct   sockaddr_in);
      int access_skt = accept(skt, (struct sockaddr *)&c_skt, &s_size);
      
      //獲取數(shù)據(jù) 
      char buf[1024];
      if (recv(access_skt, buf, 1024, 0) == -1) {
       exit(1);
      }
      
      printf("%s",buf);
     } 
    

    接下來我們對請求頭進行對應的操作。

    2.6 請求處理層編寫

    得到請求后開始編寫處理層。繼續(xù)接著代碼往下寫沒有層級,編寫一個函數(shù)名為 req,該函數(shù)接收請求信息與一個建立好的連接為參數(shù):

    void req(char* buf, int access_socket) 
    {
    }
    

    然后先在 while 循環(huán)中傳遞需要的值:

    req(buf, access_skt);
    

    接著開始編寫 req 函數(shù),首先在 req 函數(shù)中標記當前目錄下:

    char arguments[BUFSIZ];  
    strcpy(arguments, "./");
    

    隨后分離出請求與參數(shù):

    char command[BUFSIZ];     
    sscanf(request, "%s%s", command, arguments+2);
    

    接著我們標記一些頭元素:

    char* extension = "text/html";   
    char* content_type = "text/plain";     
    char* body_length = "Content-Length: ";
    

    接著獲取請求參數(shù),若獲取 index.html,就獲取當前路徑下的該文件:

    FILE* rfile= fopen(arguments, "rb");
    

    獲取文件后表示請求 ok,我們先返回一個 200 狀態(tài):

    char* head = "HTTP/1.1 200 OK\r\n";    
    int len; 
    char ctype[30] = "Content-type:text/html\r\n";   
    len = strlen(head);
    

    接著編寫一個發(fā)送函數(shù) send_:

    int send_(int s, char *buf, int *len) 
    {
     int total;          
     int bytesleft;                                
     int n;
     total=0;
     bytesleft=*len;
     while(total < *len) 
     {
      n = send(s, buf+total, bytesleft, 0);
      if (n == -1) 
      {
       break;
      }
      total += n;
      bytesleft -= n;
     }
     *len = total;          
     return n==-1?-1:0;         
    }
    

    send 函數(shù)功能并不難在此不再贅述,就是一個遍歷發(fā)送的邏輯。隨后發(fā)送 http 響應與文件類型:

    send_(send_to, head, &len);
    len = strlen(ctype);
    send_(send_to, ctype, &len);
    

    隨后獲得請求文件的描述,需要添加頭文件#include <sys/stat.h>使用fstat,且向已連接的通信發(fā)生必要的信息 :

    //獲取文件描述
    struct stat statbuf;
    char read_buf[1024];       
    char length_buf[20];
    fstat(fileno(rfile), &statbuf);
    itoa( statbuf.st_size, length_buf, 10 );
    send(client_sock, body_length, strlen(body_length), 0);
    send(client_sock, length_buf, strlen(length_buf), 0);
    
    send(client_sock, "\n", 1, 0);
    send(client_sock, "\r\n", 2, 0);
    

    最后發(fā)送數(shù)據(jù):

    //·數(shù)據(jù)發(fā)送
    char read_buf[1024]; 
    len = fread(read_buf ,1 , statbuf.st_size, rfile);
    if (send_(client_sock, read_buf, &len) == -1) { 
     printf("error!");   
    }
    

    最后訪問地址 http://127.0.0.1:8080/index.html,得到當前目錄下 index.html 文件數(shù)據(jù),并且在瀏覽器渲染:

    所有代碼如下:

    #include <WinSock2.h>
    #include<stdio.h> 
    #include <sys/stat.h> 
    
    int send_(int s, char *buf, int *len) {
     int total;          
     int bytesleft;                                
     int n;
     total=0;
     bytesleft=*len;
     while(total < *len) 
     {
      n = send(s, buf+total, bytesleft, 0);
      if (n == -1) 
      {
       break;
      }
      total += n;
      bytesleft -= n;
     }
     *len = total;          
     return n==-1?-1:0;         
    }
    
    void req(char* request, int client_sock) {   
     char arguments[BUFSIZ];  
     strcpy(arguments, "./");
     
     char command[BUFSIZ];     
     sscanf(request, "%s%s", command, arguments+2);
     
     char* extension = "text/html";   
     char* content_type = "text/plain";     
     char* body_length = "Content-Length: ";
     
     FILE* rfile= fopen(arguments, "rb");
     
    
     char* head = "HTTP/1.1 200 OK\r\n";    
     int len; 
     char ctype[30] = "Content-type:text/html\r\n";   
     len = strlen(head);
      
     send_(client_sock, head, &len);
     len = strlen(ctype);
     send_(client_sock, ctype, &len);
     
    
     struct stat statbuf;
           
     char length_buf[20];
     fstat(fileno(rfile), &statbuf);
     itoa( statbuf.st_size, length_buf, 10 );
     send(client_sock, body_length, strlen(body_length), 0);
     send(client_sock, length_buf, strlen(length_buf), 0);
    
     send(client_sock, "\n", 1, 0);
     send(client_sock, "\r\n", 2, 0);
     
    
     char read_buf[1024]; 
     len = fread(read_buf ,1 , statbuf.st_size, rfile);
     if (send_(client_sock, read_buf, &len) == -1) { 
      printf("error!");   
     }
     
     return;
    }
    
    
    int main(){
     WSADATA wsaData;
     if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) {
      exit(1);
     }
    
     int skt = socket(PF_INET, SOCK_STREAM, 0);
     if (skt == -1) {         
      return -1;
     }
    
     struct sockaddr_in server_addr;
     server_addr.sin_family = AF_INET;
     server_addr.sin_port = htons(8080);
     server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
     memset(&(server_addr.sin_zero), '\0', 8);
    
     if (bind(skt, (struct sockaddr *)&server_addr,sizeof(server_addr)) == -1) {       
      return -1; 
     } 
    
     if (listen(skt, 10) == -1 ) {    
      return -1;
     }
     
     while(1){
    
      printf("Listening ... ...\n");
      struct sockaddr_in c_skt; 
      int s_size=sizeof(struct   sockaddr_in);
      int access_skt = accept(skt, (struct sockaddr *)&c_skt, &s_size);
    
      char buf[1024];
      if (recv(access_skt, buf, 1024, 0) == -1) {
       exit(1);
      }
      
      req(buf, access_skt);
     } 
     
    }
    

    小伙伴們可以編寫更加靈活的指定資源類型、錯誤處理等完善這個 demo。

    文章目錄

      • 一、實驗名稱
      • 二、實驗目的
      • 三、實驗內(nèi)容和要求
      • 四、實驗環(huán)境
      • 五、操作方法與實驗步驟
      • 六、實驗數(shù)據(jù)記錄和結果分析

    一、實驗名稱

    建立聊天工具

    私信小編01即可獲取大量python學習資源

    二、實驗目的

    掌握Socket編程中流套接字的技術,實現(xiàn)多臺電腦之間的聊天。

    三、實驗內(nèi)容和要求

    vii.掌握利用Socket進行編程的技術
    viii.必須掌握多線程技術,保證雙方可以同時發(fā)送
    ix.建立聊天工具
    x.可以和多個人同時進行聊天
    xi.必須使用圖形界面,顯示雙方的語錄

    四、實驗環(huán)境

    PC多臺,操作系統(tǒng)Win7,win10(32位、64位)
    具備軟件python3.6 。

    五、操作方法與實驗步驟

    服務端
    1.調(diào)入多線程、與scoket包,用于實現(xiàn)多線程連接
    2.記錄本地地址與端口,開啟監(jiān)聽,等待請求
    3.收到某個客戶端的請求,建立連接,為每一個客戶端分配一個線程,并記錄客戶端地址與端口

    4.收到某個客戶端發(fā)送的數(shù)據(jù),將數(shù)據(jù)轉發(fā)給所有與服務器連接的客戶機。
    5.當某個客戶端斷開連接,通知所有與服務器連接的客戶機。
    6.服務器一直保持監(jiān)聽狀態(tài),等待其他客戶端接入服務器
    7.代碼

    import socket
    import threading
    
    num=0
    
    def chat(service_client_socket,addr): 
        # 等待接收客戶端消息存放在2個變量service_client_socket和addr里
        if not addr in user:  
            print('Accept new connection from %s:%s...' % addr)
            # 如果addr不在user字典里則執(zhí)行以下代碼
            for scs in serv_clie_socket: 
                serv_clie_socket[scs].send(data +' 進入聊天室...'.encode('utf-8'))  
                # 發(fā)送user字典的data和address到客戶端
            user[addr]=data.decode('utf-8')  #data 是最新進入聊天室的客戶,解壓后放入user
            serv_clie_socket[addr]=service_client_socket #將服務器與服務器端口號為addr的套接字放入字典
            # 接收的消息解碼成utf-8并存在字典user里,鍵名定義為addr
        #print("可以開始聊天了>>>>>>")       
        # 如果addr在user字典里,跳過本次循環(huán)
        while True:
            d=service_client_socket.recv(1024)
            if (('EXIT'.lower() in d.decode('utf-8'))|(d.decode('utf-8')=='error1')):
                #如果EXIT在發(fā)送的data里
                name=user[addr]   
                #user字典addr鍵對應的值賦值給變量name
                user.pop(addr) 
                serv_clie_socket.pop(addr)     
                #刪除user里的addr
                for scs in serv_clie_socket:     
                    #從user取出address
                    serv_clie_socket[scs].send((name + ' 離開了聊天室...').encode('utf-8'))     
                    #發(fā)送name和address到客戶端
                print('Connection from %s:%s closed.' % addr)
                global num
                num=num-1
                break
            else: 
                print('"%s" from %s:%s' %(d.decode('utf-8'), addr[0], addr[1]))  
                for scs in serv_clie_socket:    
                    #從user遍歷出address
                    if serv_clie_socket[scs] !=service_client_socket:  
                        #address不等于addr時,執(zhí)行下面的代碼
                        serv_clie_socket[scs].send(d)     
                        #發(fā)送data到客戶端
    
    s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # 創(chuàng)建socket對象
    
    addr=('127.0.0.1', 9999)
    s.bind(addr)  # 綁定地址和端口
    
    s.listen(128)
    
    print('TCP Server on', addr[0], ":",addr[1],"......")
    
    user={}  # 存放字典{addr:name}
    serv_clie_socket={} #存放{socket:不同線程的套接字}
    while True:
        try:
            print("等待接收客戶端的連接請求....")
            service_client_socket, addr=s.accept() # 等待接收客戶端的連接請求
            print("接收到客戶端的連接請求....")
        except ConnectionResetError:
            print('Someone left unexcept.')
        data=service_client_socket.recv(1024)
        if data.decode()=='error1':
            print(addr,"關閉了登錄窗口。。。")
            continue
        print("data=",data.decode())
        
             
        #為服務器分配線程
        num=num+1
        r=threading.Thread(target=chat, args=(service_client_socket,addr), daemon=True) 
        r.start()
        print("聊天室人數(shù):",num)
    
    
    


    客戶端
    1.調(diào)入多線程、與scoket包,用于實現(xiàn)多線程連接,調(diào)入tkinter包,用于圖形化頁面展示
    2.記錄本地地址與端口,向服務器發(fā)送連接請求,建立持續(xù)連接
    3.圖形化登錄界面,記錄輸入的用戶名,發(fā)送給服務器

    4.進入聊天界面,從服務器接收到的消息顯示在左邊,發(fā)送給服務器的消息顯示在右邊
    5.退出時,彈出警示界面。退出后,與服務器斷開連接,結束。
    6.代碼
    7.其他:客戶端代碼中的server改成服務器地址,客戶端可以在不同的電腦上運行連接服務器,通過服務器與其他的客戶端通訊。

    #客戶端
    import tkinter
    from tkinter import font
    import tkinter.messagebox
    import socket
    import threading
    import time
    
    string=''
    def my_string(s_input):
        string=s_input.get()
    
    def Send(sock):
        '''
            發(fā)送數(shù)據(jù)的方法
            參數(shù):
                sock:定義一個實例化socket對象
                server:傳遞的服務器IP和端口
        '''
        if string!='':
            message=name + ' : ' + string
            data=message.encode('utf-8')
            sock.send(data)
            if string.lower()=='EXIT'.lower():
                exit()
    
    
    def recv(sock):
        sock.send(name.encode('utf-8'))
        while True:
            data=sock.recv(1024)
            #加一個時間戳
            time_tuple=time.localtime(time.time())
            str=("{}點{}分".format(time_tuple[3],time_tuple[4]))
            rrecv=tkinter.Label(t,text=data.decode('utf-8'),width=40,anchor='w',bg='pink')#接收的消息靠左邊
            rrecv.pack()
    
    def left():
        global string
        string=rv1.get()
        Send(s)
        if string!='':
            rleft=tkinter.Label(t,text=string,width=40,anchor='e')#發(fā)送的消息靠右邊
            rleft.pack()
            rv1.set('')
    
    def Creat():
        global name
        name=n.get()
        
        #接收進程
        tr=threading.Thread(target=recv, args=(s,), daemon=True)
        # daemon=True 表示創(chuàng)建的子線程守護主線程,主線程退出子線程直接銷毀
        tr.start()
         
        l.destroy()
        e.destroy() 
        b.destroy()
        t.title("聊天室")
        t.geometry("500x600")
        rL0=tkinter.Label(t,text='%s的聊天室'%name,width=40)
        rL0.pack()
        rL1=tkinter.Label(t,text='請輸入消息:',width=20, height=1)
        rL1.place(x=0,y=450)
        rE1=tkinter.Entry(t, textvariable=rv1)
        rE1.place(x=200,y=450) 
        rB1=tkinter.Button(t, text="發(fā)送",command=left)  
        rB1.place(x=380,y=450)
        #發(fā)送進程
    
    def JieShu():
        tkinter.messagebox.showwarning(title='你確定退出嗎?', message='剛才你點擊了關閉按鈕')
        s.send("error1".encode('utf-8'))
        exit(0)   
        
    s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)    
    server=('10.100.207.40', 9999)
    s.connect(server)#建立連接
    t=tkinter.Tk()
    t.title("多人聊天室")
    t.geometry("300x200+500+200")
    l=tkinter.Label(t,text='多人聊天室歡迎您,請輸入你的名稱',width=40, height=8)
    l.pack()
    n=tkinter.StringVar()
    e=tkinter.Entry(t, width=15,textvariable=n)
    e.pack() 
    rv1=tkinter.StringVar()
    name=n.get()
    
    b=tkinter.Button(t, text="登錄",width=40, height=10,command=Creat) 
    
    b.pack()
    t.protocol("WM_DELETE_WINDOW", JieShu)
    t.mainloop()
    
    s.close()
    

    六、實驗數(shù)據(jù)記錄和結果分析

    1.服務器啟動,等待客戶機連接請求

    2.客戶端請求服務,客戶端彈出登錄窗口,輸入用戶名登錄

    3.服務器接收到請求,分配端口,并持續(xù)監(jiān)聽其他客戶機的請求



    4.客戶端登陸后進入聊天窗口

    5.進入聊天室的用戶,發(fā)送消息,其他用戶都可以接收到,服務器也能看到

    6.客戶機退出連接,其他用戶都可以接收到,服務器也能看到

    7.其他客戶機可以中途進入聊天室

網(wǎng)站首頁   |    關于我們   |    公司新聞   |    產(chǎn)品方案   |    用戶案例   |    售后服務   |    合作伙伴   |    人才招聘   |   

友情鏈接: 餐飲加盟

地址:北京市海淀區(qū)    電話:010-     郵箱:@126.com

備案號:冀ICP備2024067069號-3 北京科技有限公司版權所有