網絡編程:Linux平台下聊天室程序的實現


網絡編程:Linux平台下聊天室程序的實現

1.直接跳轉到Linux端代碼


一、實驗目的

  1. 學習第18章“多線程服務器端的實現”,掌握線程創建、線程同步的原理和實現方法。
  2. 在Linux操作系統上編寫基於多線程的聊天室程序。

二、實驗內容

1、在Linux操作系統上編寫多線程並發服務器端:
(1)參考第18章相應程序,實現基於多線程的聊天室程序。
(2)為每一個接入的客戶端創建線程並適當運用線程同步技術,讓多個客戶端之間可以交換信息。
(3)啟動服務器后創建兩個以上客戶端並建立連接,驗證客戶端發送的消息是否可以被所有客戶端收到。

Linux端效果圖如下:

Linux端的(采用UOS+VScode+g++):
image

Linux端代碼如下:

1. 服務器端:
#include<bits/stdc++.h>
#include<arpa/inet.h>
#include<netdb.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<pthread.h>
#include<unistd.h> 
using namespace std;


#define listennum 20              //最大監聽隊列    

int sock,i;
int fds[100];//客戶端的socketfd,100個元素,fds[0]~fds[99]
static int maxi=0;//maxi表示當前client數組中最大的用戶的i值

static int client[10];//最大的在線用戶數量

void* recvandsend(void* p){
    int fd = *(int*)p;
    cout<<"客戶端:"<<fd<<" 進入聊天室";
    while(1){
        char buf[100] = {};
        if (recv(fd,buf,sizeof(buf),0) <= 0){
            int i;
            for (i = 0;i < 10;i++){
                if (fd == fds[i]){
                    fds[i] = 0;
                    break;
                }
            }
                cout<<fd<<" 已退出!"<<endl;
                pthread_exit(NULL);
        }
        //把服務器接受到的信息發給所有的客戶端
        for (int m = 0;m < 10;m++){
        if (fds[m] != 0){
            cout<<buf<<endl;
            send(fds[m],buf,strlen(buf),0);
        }
    }
    }
}
int main()
{
       struct sockaddr_in server_addr;
       int portnumber;
       int thr_id; 

       bzero(client,sizeof(client));//置字節字符串所有字節為零且包括'\0'
 
       //創建套接字

       if((sock=socket(AF_INET,SOCK_STREAM,0))==-1)
       {
              cout<<"套接字連接出錯!"<<strerror(errno)<<endl;
              exit(1);
       }

       //設置套接字相關屬性

       bzero(&server_addr,sizeof(struct sockaddr_in));
       server_addr.sin_family=AF_INET;
       server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
       server_addr.sin_port=htons(1234);

       /* 捆綁 sock 描述符 */

       if(bind(sock,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1)
       {
              cout<<"捆綁出錯!"<<strerror(errno)<<endl;
              exit(1);
       }
       /* 監聽 sock 描述符 */

       if(listen(sock,listennum)==-1)
       {
              cout<<"監聽出錯!"<<strerror(errno)<<endl;
              exit(1);
       }
       cout<<"歡迎來到戈小戈聊天室^-^"<<endl;
     while(1){
        struct sockaddr_in fromaddr;
        socklen_t len = sizeof(fromaddr);
        int fd = accept(sock,(struct sockaddr *)(&fromaddr),&len);
        if (fd == -1){
            cout<<"客戶端連接出錯...\n";
            continue;
        }
        for (int i = 0;i < 10;i++){
            if (fds[i] == 0){
                //記錄客戶端的socket
                fds[i] = fd;
                //有客戶端連接之后,啟動線程給此客戶服務
                pthread_t tid;
                pthread_create(&tid,0,recvandsend,&fd);
                break;
            }
        if (i==10){
            //發送給客戶端說聊天室滿了
            string str = "聊天室已滿!";
            send(fd,&str,sizeof(str),0); 
            close(fd);
        }
        }
    }

}
//g++ 網絡編程作業7服務器端.cpp -o test2 -lpthread
2. 客戶端:
#include<bits/stdc++.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include<pthread.h>
#include<unistd.h> 
using namespace std; 

static int  sock;

void *recvfromserver(void *)        //接受服務器消息線程入口函數

{
       char mes[1024];
       int nbytes=0;
       while(1)
       {
              bzero(mes,sizeof(mes));//置字節字符串所有字節為零且包括'\0'
              nbytes=read( sock,mes,sizeof(mes));
              if(nbytes>0)
              {
                     mes[nbytes]='\0';
                     cout<<mes<<endl;
              }
       }
       pthread_exit(NULL);
}

int main()
{
       char buffer[1024];
       struct sockaddr_in  sock_addr;
       char clientname[1024];//客戶端昵稱
       char mes[1024];
       pthread_t  p_thread;       

       //設置套接字相關屬性
       bzero(& sock_addr,sizeof( sock_addr));//置字節字符串所有字節為零且包括'\0'
       sock_addr.sin_family=AF_INET;
       sock_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
       sock_addr.sin_port = htons(1234);

 
       //創建套接字
       sock = socket(AF_INET,SOCK_STREAM,0);
       if(connect( sock,(struct sockaddr *)(& sock_addr),sizeof(struct sockaddr))==-1)
       {
              cout<<"連接失敗!"<<strerror(errno)<<endl;
              exit(1);
       }
       /* 連接成功*/
       cout<<"歡迎來到聊天室"<<endl<<"請輸入用戶昵稱"<<endl;
       fgets(clientname, sizeof( clientname), stdin);
       cout<<endl<<"開始聊天吧(輸入Q/q退出聊天室)"<<endl;

       int thr_id =pthread_create(&p_thread, NULL, recvfromserver, NULL);//創建線程

       while(1)
       {
              bzero(buffer,sizeof( buffer));//置字節字符串所有字節為零且包括'\0'
              bzero(mes,sizeof( mes));//置字節字符串所有字節為零且包括'\0'
              fgets(buffer, sizeof( buffer), stdin);
              if(!strcmp(buffer, "q\n") || !strcmp(buffer, "Q\n"))
                     break;    
              strcat(mes,clientname);
              strcat(mes,buffer);
              if((write( sock,mes,strlen(mes)))==-1)
              {
                     cout<<"傳輸錯誤!"<<strerror(errno)<<endl;
                     exit(1);
              }        
              
       }

       /* 結束 */
       close(sock);
       exit(0);
}
//g++ 網絡編程作業7客戶端.cpp -o test1 -lpthread


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM