Linux期末大作业

今天昨天终于把上学期的Linux期末大作业写完了,简单来说就是一个终端下的聊天室,下面简单贴一下代码。
服务器端:

// 服务器端,用于接收客户端信息
#include <stdio.h>
#include <ctype.h>
#include <strings.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <pthread.h>
#define PORT 12345
#define Max 10 // 最大连接数,也就是聊天室最高在线人数
#define MAXSIZE 4096
#define TRUE 1
#define FALSE 0
int fdt[Max] = {0};
char message[MAXSIZE];
// 发送消息
void SendToClient(int fd, char *buf, int Size)
{
    int i;
    int e;
    for (i = 0; i < Max; i++)
    {
        // 给其他在线用户发送消息
        if ((fdt[i] != 0) && (fdt[i] != fd))
            send(fdt[i], buf, Size, 0);
    }
    bzero(buf, sizeof(buf));
}
// 子线程函数
void *pthread_service(void *sfd)
{
    int fd = *(int *)sfd;
    while (TRUE)
    {
        int i;
        int numbytes;
        numbytes = recv(fd, message, MAXSIZE, 0);
        if (numbytes <= 0)
        {
            for (i = 0; i < Max; i++)
            {
                if (fd == fdt[i])
                {
                    fdt[i] = 0;
                }
            }
            printf("客户端 %d 已退出\n", fd);
            break;
        }
        printf("来自客户端 %d 的信息: \n", fd);
        printf("用户%s\n", message);
        // 开始转发
        SendToClient(fd, message, numbytes);
        bzero(message, MAXSIZE);
    }
    close(fd);
    pthread_exit(0);
}
int main()
{
    int listenfd, connectfd;
    struct sockaddr_in server;
    struct sockaddr_in client;
    int sin_size;
    sin_size = sizeof(struct sockaddr_in);
    int number = 0;
    if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        perror("创建 socket 失败");
        exit(1);
    }
    bzero(&server, sizeof(server)); // 防止内存出错
    server.sin_family = AF_INET;
    server.sin_port = htons(PORT);
    server.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(listenfd, (struct sockaddr *)&server, sizeof(struct sockaddr)) == -1)
    {
        perror("bind() 错误");
        exit(1);
    }
    if (listen(listenfd, 1) == -1)
    {
        perror("listen() 错误\n");
        exit(1);
    }
    printf("等待连接...\n");
    while (TRUE)
    {
        if ((connectfd = accept(listenfd, (struct sockaddr *)&client, &sin_size)) == -1)
        {
            perror("accept() 错误\n");
            exit(1);
        }
        if (number >= Max)
        {
            printf("同时在线人数已达上限\n");
            close(connectfd);
        }
        int i;
        for (i = 0; i < Max; i++)
        {
            if (fdt[i] == 0)
            {
                fdt[i] = connectfd;
                break;
            }
        }
        pthread_t tid;
        pthread_create(&tid, NULL, (void *)pthread_service, &connectfd);
        pthread_detach(tid);
        number = number + 1;
    }
    close(listenfd);
    return 0;
}

客户端

// 客户端,用于登陆注册以及聊天功能的实现
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <pthread.h>
#define PORT 12345
#define MAXSIZE 4096
#define TRUE 1
#define FALSE 0
char sendbuf[MAXSIZE];
char recvbuf[MAXSIZE];
char data[100][100];
char name[100];
char password[100];
int fd;
// 用以接收信息
void *pthread_recv(void *ptr)
{
    while (TRUE)
    {
        if ((recv(fd, recvbuf, MAXSIZE, 0)) == -1)
        {
            printf("recv() error\n");
            exit(1);
        }
        printf("%s", recvbuf);
        memset(recvbuf, 0, sizeof(recvbuf));
    }
}
int main(int argc, char *argv[])
{
    int numbytes;
    char buf[MAXSIZE];
    struct hostent *hostent;
    struct sockaddr_in server;
    if (argc != 2)
    {
        printf("使用方法: %s <您的IP地址>\n", argv[0]);
        exit(1);
    }
    if ((hostent = gethostbyname(argv[1])) == NULL)
    {
        printf("gethostbyname() error\n");
        exit(1);
    }
    if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        printf("socket() error\n");
        exit(1);
    }
    bzero(&server, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(PORT);
    server.sin_addr = *((struct in_addr *)hostent->h_addr);
    if (connect(fd, (struct sockaddr *)&server, sizeof(struct sockaddr)) == -1)
    {
        printf("连接失败\n");
        exit(1);
    }
    printf("连接成功\n");
    char str[] = "已进入聊天室\n";
    printf("请输入用户名(若用户名不存在将进行自动创建用户):");
    fscanf(stdin, "%s", name); // 读取一行
    printf("请输入密码:");
    fscanf(stdin, "%s", password); // 读取一行
    char tmp[10];
    fgets(tmp, sizeof(tmp), stdin);
    FILE *fp = fopen("users.txt", "r+");
    int flag1 = 0; // 为1表示登录成功
    int flag2 = 0; // 为1表示密码错误,为0表示注册
    // 奇数行是用户名
    // 偶数行是密码
    int num = 0;
    if (NULL == fp) // 判断一下文件是否成功打开
    {
        printf("open failed.\n");
        return 0;
    }
    while (!feof(fp))
    {
        fscanf(fp, "%s", data[num]);
        // printf("%s\n", data[num]);
        num++;
    }
    for (int i = 0; i < num - 1; i++)
    {
        if (strcmp(name, data[i]) == 0 && strcmp(password, data[i + 1]) == 0)
        {
            flag1 = 1; // 登录成功
        }
        else if (strcmp(name, data[i]) == 0 && strcmp(password, data[i + 1]) != 0)
        {
            flag2 = 1; // 用户名对了但是密码错了
        }
    }
    if (flag1 == 1)
    { // 登录成功
        printf("登陆成功,输入exit可退出聊天室\n");
        send(fd, name, (strlen(name)), 0);
        send(fd, str, (strlen(str)), 0);
        // 创建子线程
        pthread_t tid;
        pthread_create(&tid, NULL, pthread_recv, NULL);
        pthread_detach(tid);
        // 客户端的输入
        while (TRUE)
        {
            memset(sendbuf, 0, sizeof(sendbuf));
            fgets(sendbuf, sizeof(sendbuf), stdin);
            if (strcmp(sendbuf, "exit\n") == 0)
            {
                memset(sendbuf, 0, sizeof(sendbuf));
                printf("您已退出聊天室\n");
                send(fd, sendbuf, (strlen(sendbuf)), 0);
                break;
            }
            send(fd, name, (strlen(name)), 0);
            send(fd, ":", 1, 0);
            send(fd, sendbuf, (strlen(sendbuf)), 0);
        }
        close(fd);
    }
    else
    {
        if (flag2 == 1)
        {
            printf("密码错误\n");
            fclose(fp);
        }
        else
        {
            printf("注册成功,已帮您自动登录,输入exit可退出聊天室\n");
            // 将用户信息写入users.txt文件中
            fprintf(fp, "\n%s", name);
            fprintf(fp, "\n%s", password);
            fclose(fp);
            send(fd, name, (strlen(name)), 0);
            send(fd, str, (strlen(str)), 0);
            // 创建子线程
            pthread_t tid;
            pthread_create(&tid, NULL, pthread_recv, NULL);
            pthread_detach(tid);
            // 客户端的输入
            while (TRUE)
            {
                memset(sendbuf, 0, sizeof(sendbuf));
                fgets(sendbuf, sizeof(sendbuf), stdin);
                if (strcmp(sendbuf, "exit\n") == 0)
                {
                    memset(sendbuf, 0, sizeof(sendbuf));
                    printf("您已成功退出聊天室\n");
                    send(fd, sendbuf, (strlen(sendbuf)), 0);
                    break;
                }
                send(fd, name, (strlen(name)), 0);
                send(fd, ": ", 2, 0);
                send(fd, sendbuf, (strlen(sendbuf)), 0);
            }
            close(fd);
        }
    }
    return 0;
}

同目录下应存放一个users.txt文件,用于存储用户信息,其中偶数行表示用户名,奇数行表示密码。

添加新评论