Linux網絡編程(多人在線聊天系統)


一、首先是服務器的建立

       首先是一個信號終止程序,發信號ctrl+c終止程序,而是是初始化網絡通信.

       創建一個描述符負責綁定服務器和監聽服務器接收客戶端的消息.

       socket()->sockaddr_in->bind->listen(准備就緒)

       開始接收客戶端消息.start()函數

       首先是聲明一個結構體用來存儲客戶端的消息,利用accept()函數來創建一個新的

       描述符來接收,這里有阻塞效果,也即是說連接的時候只能一個一個的連.

       然后是分離線程處理這個sockfd的連接.

       pthread_create(&pid,0,pthread_deal,&sockfd1);

       線程主要是先做線程的分離,然后是取得它們的sockfd描述符,把這個客戶端的信息

       存儲到一個結構體數組中.然后是調用循環發送到各個客戶端的函數,來發送消息.

       當接收函數recv(sockfd,buf,sizeof(buf)) == 0 的時候,表示有客戶端退出,這時

       就把這個在結構體數組的相應的fd置為0

      

#include "server.h"
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

int sockfd; //服務器本身的描述符
struct User u[200] = {}; //用來保存用戶的信息
int size;//數組的下標,同時也是客戶端的個數

void init(void) //通信准備工作
{
    printf("聊天室服務器馬上啟動....\n");
    sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(-1 == sockfd)
    {
        perror("fail to socket");
        printf("服務器故障!\n");
        exit(-1);
    }
    //准備通信地址和綁定服務器
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(2222); //端口的值,轉換成網絡的格式
    addr.sin_addr.s_addr = inet_addr("172.16.1.21");
    if(-1 == bind(sockfd,(struct sockaddr*)&addr,sizeof(addr)))
    {
        perror("fail to bind");
        exit(-1);
    }
    printf("bind is ok,歡迎訪問!\n");
    //設置監聽
    if(-1 != listen(sockfd,200))
    {
        printf("監聽已經設置,一切准備就緒!\n");
    }
}

void send_msg(char *p_msg) //發送消息的函數
{
    int num = 0;
    for(num = 0;num < size;num++)
    {
        if(u[num].fd) //如果是有效的時候才發送
        {
            send(u[num].fd,p_msg,sizeof(p_msg),0);
        }
    }
}

void* pthread_deal(void* p) //線程處理函數
{
    pthread_detach(pthread_self());
    int fd2 = *(int*)p; //取得客戶端的sockfd
    u[size].fd = fd2;  //放入結構體中
    char name[20] = {};
    int res = recv(fd2,name,sizeof(name),0);
    if(res > 0)
    {
        strcpy(u[size].name,name);//存放用戶名
    }
    size++;
    char user[100] = {};
    sprintf(user,"%s悄悄的進來了!(*^__^*) 嘻嘻……\n",name);
    send_msg(user);
    while(1)
    {
        if(recv(fd2,name,sizeof(name),0) == 0) /*返回0表示有客戶端退出*/
        {
            u[size-1].fd = 0; //把退出的客戶端的結構描述符置換成0
        }
    }
}

void start(void)
{
    printf("success to start server,let's go!\n");
    while(1)
    {
        struct sockaddr_in client;//存儲接收到的客戶端的信息
        socklen_t length = sizeof(client);
        //接收客戶端的信息,會有阻塞效果,sockfd1標記客戶端
        int sockfd1 = accept(sockfd,(struct sockaddr*)&client,&length);
        if(sockfd1 == -1)
        {
            perror("fail to accept!");
            continue;  //繼續連接
        }
        printf("%s連接上來了\n",inet_ntoa(client.sin_addr));
        /*連接成功之后,就啟動線程*/
        pthread_t pid;//線程id
        pthread_create(&pid,0,pthread_deal,&sockfd1);
    }
}

void sig_exit(int signo ) //子定義信號關閉服務器函數
{
    close(sockfd);//關閉服務器端口
    printf("服務器成功關閉!\n");
    exit(0);
}
int main(void)
{
    printf("按ctrl+c關閉聊天室服務器!\n");
    signal(SIGINT,sig_exit);
    init();//初始化,服務器通信准備工作
    start();//啟動服務(開始處理聊天信息)
    return 0;
}

2.客戶端的編寫.

  

      


免責聲明!

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



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