实现一个聊天室功能的软件

服务端做数据处理:每一个用户是一个客服端,每一个用户上线服务端记录。每个用户的发言都会被服务端通知到其它给用户。

Makefile
all: server client

server: chat_room.c
    gcc chat_room.c -o server -g -DDEBUG
client: client.c
    gcc client.c -o client -g
clean:
    rm server client
.PHONY: clean

usr_info.txt
Teach.Zhang
Teach.Gao
Teach.Wu
/* client.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/mman.h>

#define SERV_PORT 8000
#define SERV_IP "127.0.0.1"

int main(int argc, char *argv[])
{
    char *usr_name;
    int sfd, n, i;
    struct sockaddr_in serv_addr;
    char buf[1024];
    pid_t *pid, tpid;

    usr_name = argv[1];

    sfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sfd == -1)
        return -1;

    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(SERV_PORT);
    inet_pton(AF_INET, SERV_IP, &serv_addr.sin_addr.s_addr);

    sprintf(buf, "syn %s", usr_name);
    n = sendto(sfd, buf, strlen(buf), 0,
        (struct sockaddr *)&serv_addr, sizeof(serv_addr));
    n = recvfrom(sfd, buf, 1024, 0, NULL, NULL);
    buf[n] = '\0';
    if(strcmp(buf, "OK")){
        printf("fail to login...\n");
        return 0;
    }

    pid = (pid_t *)mmap(NULL, sizeof(pid) * 2, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);

    for(i = 0; i < 2; i++){
        if((tpid = fork()) == 0)
            break;
        pid[i] = tpid;
    }
    if(i == 0){
        while(1){
            n = read(STDIN_FILENO, buf, 1024);
            if(buf[0] == '#')
                break;
            n = sendto(sfd, buf, n, 0,
                (struct sockaddr *)&serv_addr, 
                sizeof(serv_addr));
        }
        
        kill(pid[1], SIGUSR1);

        return 0;
    }else if(i == 1){
            while(1){
                n = recvfrom(sfd, buf, 1024, 0, NULL, NULL);
                write(STDOUT_FILENO, buf, n);
            }
            
            return 0;
    }else
        for(i = 0; i < 2; i++)
            wait(NULL);

tryagain:
    sprintf(buf, "fin %s", usr_name);
    n = sendto(sfd, buf, strlen(buf), 0,
        (struct sockaddr *)&serv_addr, sizeof(serv_addr));
    n = recvfrom(sfd, buf, 1024, 0, NULL, NULL);
    buf[n] = '\0';
    if(strcmp(buf, "OK")){
        sleep(1);
        printf("fail to logout...\n");
        goto tryagain;
    }

    close(sfd);
    
    return 0;
}
/* chat_room.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>

typedef struct usr
{
    char *usr_name;
    struct sockaddr_in addr;
    int is_online;
    struct usr *next;
}usr_t;

usr_t *head = NULL;

usr_t *new_node(const char *usr_name)
{
    usr_t *p;

    p = (usr_t *)malloc(sizeof(usr_t));
    if(p == NULL)
        return NULL;
    p->usr_name = (char *)malloc(sizeof(char) * (strlen(usr_name) + 1));
    strcpy(p->usr_name, usr_name);
    p->is_online = 0;
    p->next = NULL;
    memset(&p->addr, 0, sizeof(p->addr));

    return p;
}

int insert(const char *usr_name)
{
    usr_t *p, *q;

    p = new_node(usr_name);
    if(p == NULL)
        return -1;
    if(head == NULL){
        head = p;
        return 0;
    }
    for(q = head; q->next != NULL; q = q->next);
    q->next = p;

    return 0;
}

int is_equal(struct sockaddr_in *p, struct sockaddr_in *q)
{
    return p->sin_family == q->sin_family && p->sin_port == q->sin_port && p->sin_addr.s_addr == q->sin_addr.s_addr;
}

usr_t *search_by_addr(struct sockaddr_in *addr)
{
    usr_t *p;
    for(p = head; p != NULL; p = p->next)
        if(is_equal(&p->addr, addr))
            return p;

    return NULL;
}

usr_t *search_by_name(const char *usr_name)
{
    usr_t *p;

    for(p = head; p != NULL; p = p->next)
        if(strcmp(p->usr_name, usr_name) == 0)
            break;
    return p;
}

void print(void)
{
    usr_t *p;
    char ip[20];

    for(p = head; p != NULL; p = p->next){
        printf("name : %s, ", p->usr_name);
        if(p->is_online == 0)
            printf("out-of-line, ");
        else
            printf("online, ");
        inet_ntop(AF_INET, &p->addr.sin_addr.s_addr, ip, 20);
        printf("ip : %s, ", ip);
        printf("port : %u\n", ntohs(p->addr.sin_port));
    }
}

void destroy(void)
{
    usr_t *p, *q;
    for(p = head; p != NULL; p = q){
        q = p->next;
        free(p->usr_name);
        free(p);
    }
    head = NULL;
}

int get_usr_info(const char *filename)
{
    FILE *fp;
    char buf[1024];

    fp = fopen(filename, "r");
    if(fp == NULL)
        return -1;
    while(fgets(buf, 1024, fp)){
        buf[strlen(buf) - 1] = '\0';
        insert(buf);
    }
    fclose(fp);
    return 0;
}

int sock_init(in_port_t port, const char *ip)
{
    int sfd;
    struct sockaddr_in serv_addr;

    sfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sfd == -1)
        return -1;

    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(port);
    inet_pton(AF_INET, ip, &serv_addr.sin_addr.s_addr);

    if(bind(sfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1)
        return -1;
    return sfd;
}

int main(void)
{
    int sfd, n;
    char buf[1024];
    usr_t *p; socklen_t len;
    struct sockaddr_in cli_addr;

    get_usr_info("usr_info.txt");
    sfd = sock_init(8000, "127.0.0.1");
    
    while(1){
        len = sizeof(struct sockaddr_in);
        n = recvfrom(sfd, buf, 1024, 0, 
            (struct sockaddr *)&cli_addr, &len);
        buf[n] = '\0';
        
        if(strncmp(buf, "syn", 3) == 0){ /* login */
            char *name;

            name = strstr(buf, " ");
            name++; 
            p = search_by_name(name);
            if(p == NULL)
                sendto(sfd, "fail", strlen("fail"), 0,
                    (struct sockaddr *)&cli_addr, sizeof(cli_addr));
            else{
                p->is_online = 1;
                p->addr = cli_addr;
                sendto(sfd, "OK", strlen("OK"), 0,
                    (struct sockaddr *)&cli_addr, sizeof(cli_addr));
            }
#ifdef DEBUG
            print();
#endif
        }else if(strncmp(buf, "fin", 3) == 0){ /* logout */
            char *name;

            name = strstr(buf, " ");
            name++; 
            p = search_by_name(name);
            if(p == NULL)
                sendto(sfd, "fail", strlen("fail"), 0,
                    (struct sockaddr *)&cli_addr, sizeof(cli_addr));
            else{
                p->is_online = 0;
                memset(&p->addr, 0, sizeof(p->addr));
                sendto(sfd, "OK", strlen("OK"), 0,
                    (struct sockaddr *)&cli_addr, sizeof(cli_addr));
            }
#ifdef DEBUG
            print();
#endif
        }else{ /* somebody talk */
            char msg[32];           

            p = search_by_addr(&cli_addr);
            if(p == NULL)
                continue;
            
            sprintf(msg, "%s say : ", p->usr_name);
            for(p = head; p != NULL; p = p->next){
                if(p->is_online){
                    n = sendto(sfd, msg, strlen(msg), 0,
                        (struct sockaddr *)&p->addr, sizeof(p->addr));
                    n = sendto(sfd, buf, strlen(buf), 0,
                        (struct sockaddr *)&p->addr, sizeof(p->addr));
                }
            }
        }
        printf("one data over...\n");
    }
    destroy();
    
    return 0;
}
//linux
Makefile
all: server client

server: server.c
    gcc server.c -o server -g
client: client.c
    gcc client.c -o client -g
clean:
    rm server client
.PHONY: clean
/* 一个客户端、服务器程序
客户端发送数据给服务端,服务端数据进行转换,然后发送给客户端。
//client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define SERV_IP "192.168.175.128"
#define SERV_PORT 8000
int main(void){
    int sfd, n;
    struct sockaddr_in serv_addr;
    char buf[1024];

    sfd = socket(AF_INET, SOCK_STREAM, 0);
    
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(SERV_PORT);
    inet_pton(AF_INET, SERV_IP, &serv_addr.sin_addr.s_addr);    

    n = connect(sfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
    while(1){
        n = read(STDIN_FILENO, buf, 1024);
        if(n == 0)
            break;
        write(sfd, buf, n);
        n = read(sfd, buf, 1024);
        write(STDOUT_FILENO, buf, n);
    }
    close(sfd);
    return 0;
}
//server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define SERV_IP "192.168.175.128"
#define SERV_PORT 8000
void err_sys(const char *str){
    perror(str);
    exit(1);
}

int main(void){
    int lfd;
    struct sockaddr_in serv_addr;
    int n;

    lfd = socket(AF_INET, SOCK_STREAM, 0);
    if(lfd == -1)
        err_sys("socket error");

    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(SERV_PORT);
    inet_pton(AF_INET, SERV_IP, &serv_addr.sin_addr.s_addr);

    n = bind(lfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
    if(n == -1)
        err_sys("bind error");
    n = listen(lfd, 20);
    if(n == -1)
        err_sys("listen error");

    //pause();

    while(1){
        int cfd, i;
        char buf[1024];

        cfd = accept(lfd, NULL, NULL);
        if(cfd == -1)
            err_sys("accept error");

        while(1){
            n = read(cfd, buf, 1024);
            if(n == 0){
                printf("connection closed...\n");
                break;
            }
            for(i = 0; i < n; i++)
                buf[i] = toupper(buf[i]);
            write(cfd, buf, n);
            write(STDOUT_FILENO, buf, n);
        }

        close(cfd);
    }
    printf("should not be here\n");
    return 0;
}
/* windows client */
//client.c
#include<winsock2.h>
#include<iostream>
#include<string>

using namespace std;
#pragma comment(lib, "ws2_32.lib")
int main(){
    WORD sockVersion = MAKEWORD(2, 2);
    WSADATA data;
    if (WSAStartup(sockVersion, &data) != 0)
        return 1;

    while (true){
        SOCKET clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (clientSocket == INVALID_SOCKET){
            return 1;
        }
        sockaddr_in sock_in;
        sock_in.sin_family = AF_INET;
        sock_in.sin_port = htons(8888);
        sock_in.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
        if (connect(clientSocket, (sockaddr*)&sock_in, sizeof(sock_in)) == SOCKET_ERROR){
            return 1;
        }

        string data;
        getline(cin, data);
        const char * msg;
        msg = data.c_str();
        send(clientSocket, msg, strlen(msg), 0);

        char revdata[100];
        int num = recv(clientSocket, revdata, 100, 0);
        if (num > 0){
            revdata[num] = '\0';
            cout << "Sever say:" << revdata << endl;
        }
        closesocket(clientSocket);
    }
    WSACleanup();
    return 0;
}
//server.c win server
#include<winsock2.h>
#include<iostream>
#include<string>

using namespace std;
#pragma comment(lib,"ws2_32.lib") //表示链接wpcap.lib这个库。和在工程设置里写上链入wpcap.lib的效果一样

int main(int argc, char* argv[]){
    //初始化DLL
    WORD sockVersion = MAKEWORD(2, 2); //表示使用WINSOCK2版本
    WSADATA wsdata; //用来存储系统传回的关于WINSOCK的资料
    if (WSAStartup(sockVersion, &wsdata) != 0) //连接应用程序与winsock.dll的第一个调用
        return 1;

    //创建套接字
    SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (serverSocket == INVALID_SOCKET)
        return 1;

    //绑定套接字
    sockaddr_in sockAddr;
    sockAddr.sin_family = AF_INET;
    sockAddr.sin_port = htons(8888);
    sockAddr.sin_addr.S_un.S_addr = INADDR_ANY;
    if (bind(serverSocket, (sockaddr*)&sockAddr, sizeof(sockAddr)) == SOCKET_ERROR)
        return 1;
    //开始监听
    if (listen(serverSocket, 10) == SOCKET_ERROR)
        return 1;

    SOCKET clientSocket;
    sockaddr_in client_sin;
    char msg[100];//存储传送的消息
    int flag = 0;//是否已经连接上
    int len = sizeof(client_sin);
    while (true){
        if (!flag)
            cout << "等待连接..." << endl;
        clientSocket = accept(serverSocket, (sockaddr*)&client_sin, &len);
        if (clientSocket == INVALID_SOCKET){
            flag = 0;
            return 1;
        }
        if (!flag)
            cout << "接收到一个链接:" << inet_ntoa(client_sin.sin_addr) << endl;
        flag = 1;
        int num = recv(clientSocket, msg, 100, 0);
        if (num > 0){
            msg[num] = '\0';
            cout << "Client say: " << msg << endl;
        }

        string data;
        getline(cin, data);
        const char * sendData;
        sendData = data.c_str();
        send(clientSocket, sendData, strlen(sendData), 0);
        closesocket(clientSocket);
    }
    closesocket(serverSocket);
    WSACleanup();

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

春夏与冬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值