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

1、首先是服務器的創建數組

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

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

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

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

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

       描述符來接收,這裏有阻塞效果,也便是說鏈接的時候只能一個一個的連.線程

       而後是分離線程處理這個sockfd的鏈接.code

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

       線程主要是先作線程的分離,而後是取得它們的sockfd描述符,把這個客戶端的信息blog

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

       當接收函數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.客戶端的編寫.

相關文章
相關標籤/搜索