Linux下网络编程之C语言,服务器与客户端

cpp 复制代码
//command.h
#ifndef SERVER_REMOTE_COMMAND_H 
#define SERVER_REMOTE_COMMAND_H

#include <pthread.h>
#define GROUP_SEND '1' 
#define SINGLE_SEND '2'
#define REGISER '3'
#define LOGIN '4'

typedef struct st
{
    int fd; //client fd
    char *ip; //client ip
    int port; //client port
    char name[20]; //client name
    char password[20]; //client password
    pthread_t tid; //client thread id
    struct st *next; //next node
}client_info;

#endif
cpp 复制代码
#ifndef SERVER_REMOTE_LIST_H
#define SERVER_REMOTE_LIST_H

typedef struct st client_info; // 让编译器知道这个结构体的存在


void initList(client_info **head); 
void addList(client_info *head, const client_info *node); 
void removeList(client_info *head, const client_info *node);
void printList(client_info *head);

#endif
cpp 复制代码
//main.c
#include "command.h"
#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "list.h"

#define BUF_SIZE 100

client_info *head;//client info list
FILE* chatHistory;

void fileWrite(FILE* chatHistory, char* msg)
{
    fprintf(chatHistory, "%s", msg);
    fflush(chatHistory); // 刷新缓冲区
}

pthread_mutex_t mutex;// 互斥锁

// 处理信息
void* handleClient(void*arg)
{
    client_info clientInfo = *(client_info*)arg; // 清零
    char buf[BUF_SIZE];
    while(1)
    {
        bzero(buf, BUF_SIZE); //清零 memset()
        // read 接收信息
        int len = recv(clientInfo.fd, buf, BUF_SIZE, 0);
        #ifndef DEBUG_MY
        printf("recv: %s\n", buf);
        #endif
        if(len == -1)
        {
            perror("recv");
            pthread_exit(NULL);
        }
        if(len == 0) // 接收为0==EOF  ,客户端断开连接
        {
            #ifndef DEBUG_MY
            printf("client %s closed\n", clientInfo.ip); //定位错误
            #endif

            // 移除
            pthread_mutex_lock(&mutex);
            removeList(head, &clientInfo);
            pthread_mutex_unlock(&mutex);
            close(clientInfo.fd);
            pthread_exit(NULL); // 退出线程
        }
        if(buf[0]==GROUP_SEND)//群发消息
        {
            pthread_mutex_lock(&mutex);
            #ifndef DEBUG_MY
            printf("client send %s\n", buf+1); //定位错误
            #endif
            char temp_buf[BUF_SIZE]={0};
            time_t timep;
            time(&timep);
            sprintf(temp_buf, "%s:%s:%s", clientInfo.name, buf+1,ctime(&timep));

            #ifndef DEBUG_MY
            printf("temp_buf %s\n", temp_buf); //定位错误
            #endif

            // 发送信息格式为:name:msg:time
            client_info *temp=head->next;
            while(temp!=NULL)
            {
                send(temp->fd, temp_buf, BUF_SIZE, 0);
                // 排除自己
                temp=temp->next;
            }
            // 写入聊天记录
            strcat(temp_buf, "群发消息\n");
            fileWrite(chatHistory, temp_buf);
            pthread_mutex_unlock(&mutex);
        }
        else if(buf[0]==SINGLE_SEND)//单发消息
        {
            char *p = buf + 1; //接受buf[0]后面的数据
            // strtok()函数用于将字符串分割成一个个片段
            // 规定单发消息格式为:2:ip:msg
            // strtok()函数第一次调用时,第一个参数为字符串,第二个参数为分隔符
            // 之后每次调用,第一个参数为NULL,第二个参数为分隔符
            char *ip = strtok(p, ":");
            char *msg = strtok(NULL, ":");

            #ifndef DEBUG_MY
            printf("ip:%s msg:%s", ip,msg); //定位错误
            #endif

            pthread_mutex_lock(&mutex);
            client_info *temp = head->next;
            while(temp->next!=NULL)
            {
                if (strcmp(temp->ip, ip) == 0)
                {
                    char temp_buf[BUF_SIZE];
                    sprintf(temp_buf, "%s:%s", clientInfo.ip, msg);
                    write(temp->fd, temp_buf, strlen(temp_buf));
                    // 写入聊天记录
                    strcat(temp_buf, "单发消息\n");
                    fileWrite(chatHistory, temp_buf);
                    break;
                }
                temp=temp->next;
            }
            pthread_mutex_unlock(&mutex);
        }
    }
}


int main()
{
    pthread_mutex_init(&mutex, NULL);
    initList(&head);
    chatHistory= fopen("chatHistory.txt","a+");

    int sock_fd = socket(AF_INET, SOCK_STREAM, 0);
    if(sock_fd == -1)
    {
        perror("socket");
        exit(-1);
    }
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(9000);
    server_addr.sin_addr.s_addr =INADDR_ANY;
    int opt = 1;
    setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    if(bind(sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1)
    {
        perror("bind");
        exit(-1);
    }
    if(listen(sock_fd, 10) == -1)
    {
        perror("listen");
        exit(-1);
    }
    while(1)
    {
        struct sockaddr_in client_addr;
        socklen_t len = sizeof(client_addr);
        int client_fd = accept(sock_fd, (struct sockaddr*)&client_addr, &len);
        if(client_fd == -1)
        {
            perror("accept");
            exit(-1);
        }
        // 读取账号密码
        char msg[BUF_SIZE];
        memset(msg,0, BUF_SIZE);
        int len_read = recv(client_fd, msg, BUF_SIZE, 0);
        if(len_read == -1)
        {
            perror("recv");
            exit(-1);
        }
        // 处理连接信息
        char *p = msg + 1;
        char *username = strtok(p, ":");
        char *password = strtok(NULL, ":");
        if(msg[0]==REGISER) // 注册
        {
            //添加到文件
            FILE* fp = fopen("user.txt", "a+");
            if(fp == NULL)
            {
                perror("fopen");
                exit(-1);
            }
            char un[20], pwd[20];
            int exit=0;
            while (fscanf(fp, "%s%s", un, pwd) != EOF)
            {
                if(strcmp(username,un)==0&&strcmp(password,pwd)==0)
                {
                    exit=1; //已存在
                    break;
                }
            }
            if(exit==1)
            {
                // 发送注册失败
                char *send_msg= "fail";
                write(client_fd, send_msg, strlen(send_msg));
                continue;
            }
            else if(exit==0)
            {
                // 写入文件
                fprintf(fp, "%s %s\n", username, password);
                fclose(fp);
                // 发送注册成功
                char *send_msg= "success";
                write(client_fd, send_msg, strlen(send_msg));
            }
        }
        if(msg[0]==LOGIN) //登录
        {
            //验证
            // 打开文件
            FILE* fp = fopen("user.txt", "r");
            if(fp == NULL)
            {
                perror("fopen");
                exit(-1);
            }
            // 读取文件
            char un[20];
            char pwd[20];
            while (fscanf(fp, "%s%s", un, pwd) != EOF)
            {
                if(strcmp(username, un) == 0 && strcmp(password, pwd) == 0)
                {
                    char* send_msg = "success";
                    write(client_fd, send_msg, strlen(send_msg));
                    break;
                }
            }
  		
            fclose(fp);

            char* send_msg = "fail";
            write(client_fd, send_msg, strlen(send_msg));
		continue;
         }


        client_info clientInfo;
        strcpy(clientInfo.name, username);
        strcpy(clientInfo.password, password);
        clientInfo.port = ntohs(client_addr.sin_port); //get client port
        clientInfo.fd = client_fd;
        clientInfo.ip = inet_ntoa(client_addr.sin_addr); //get client ip

        //创建线程

        pthread_t pid;
        int ret=pthread_create(&pid, NULL, handleClient, (void*)&clientInfo);

        if(ret!=0)
        {
            perror("pthread_create");
            exit(-1);
        }
        clientInfo.tid = pid;
        pthread_mutex_lock(&mutex);
        addList(head, &clientInfo);
        pthread_mutex_unlock(&mutex);
    }
}
cpp 复制代码
//user.txt

xiaobai 2222
xiaoxiao 1234
xiaoli 12345
xiaolo 1234
xiaowi 123
jjjj 2222
dddd 1111
ffff 3333

eeee 2222
fffff 33333
rrrr 2222
qwer 1234
12345 123456
123 1234
112233 445566
22333 444444
0000 2222
pppp 2222
cpp 复制代码
//chatHistory.txt


群发消息群发消息群发消息群发消息12345:qqqqqqqqqqqqq:Wed Aug  9 08:55:36 2023
群发消息
0000:qqqqqqqqqqqqqqqqqqq:Wed Aug  9 09:14:57 2023
群发消息
0000:qqqqqqqqqqqqqqqq:Wed Aug  9 09:15:54 2023
群发消息
0000:qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq:Wed Aug  9 09:17:16 2023
群发消息
0000:baibaibia:Wed Aug  9 09:17:27 2023
群发消息
pppp:qqqqqqqqqqqqqqqqqqqqqq:Wed Aug  9 17:02:51 2023
群发消息
pppp:llllllllllllllllllllllll:Wed Aug  9 17:03:20 2023
群发消息
pppp:llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息
pppp:llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll1llllllllllllllllllllllll:Wed Aug  9 17:05:13 2023
群发消息

//客户机:

//command.h

#ifndef THREAD_COMMAND_H

#define THREAD_COMMAND_H

#define GROUP_SEND '1'

#define SINGLE_SEND '2'

#define REGISER '3'

#define LOGIN '4'

#define BUF_SIZE 1024 // 缓冲区大小

#endif

//menuFunctions.h

#ifndef THREAD_MENUFUNCTION_H

#define THREAD_MENUFUNCTION_H

void menuForLoginAndRegister(int fd);

void menuForSend(int fd);

#endif

//menuFunctions.c

#include "menuFunctions.h"

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include "command.h"

#include <sys/socket.h>

void menuForLoginAndRegister(int fd)

{

printf("1.注册\n");

printf("2.登录\n");

printf("3.退出\n");

printf("请输入你的选择: ");

char choice;

scanf("%c", &choice);

getchar();

switch(choice)

{

case '1':

{

char name20={0};

char password20={0};

printf("请输入用户名: ");

scanf("%s", name);

getchar();

printf("请输入密码: ");

scanf("%s", password);

getchar();

char bufBUF_SIZE={0};//缓冲区

snprintf(buf, sizeof(buf), "%c:%s:%s", REGISER, name, password);

send(fd, buf, strlen(buf), 0);

sleep(3); //等待服务器返回注册结果

read(fd, buf, sizeof(buf));

if(buf0 == 's') //注册成功

{

printf("注册成功\n");

printf("1.聊天\n");

printf("2.退出\n");

printf("请输入你的选择: \n");

char choice1;

scanf("%c",&choice1);

getchar();

switch (choice1)

{

case '1' :

{

menuForSend(fd);

break;

}

case '2':

{

close(fd);

exit(0);

}

default:

{

printf("输入错误\n");

break;

}

}

}

else if(buf0 == 'f')

{

printf("注册失败\n");

exit(0); }

break;

}

case '2':

{

char name20;

char password20;

printf("请输入用户名: ");

scanf("%s", name);

getchar();

printf("请输入密码: ");

scanf("%s", password);

getchar();

char bufBUF_SIZE;

snprintf(buf,sizeof(buf), "%c:%s:%s", LOGIN, name, password);

send(fd, buf, strlen(buf), 0);

sleep(4); //等待服务器返回登录结果

read(fd, buf, sizeof(buf));

if(buf0 == 's') //登录成功

{

printf("登录成功\n");

menuForSend(fd);

}

else

{

printf("登录失败\n");

}

break;

}

case '3':

{

close(fd);

exit(0);

}

default:

{

printf("输入错误\n");

exit(0);

break;

}

}

}

void menuForSend(int fd)

{

while(1)

{

printf("1.群发\n");

printf("2.私聊\n");

printf("3.退出\n");

printf("请输入你的选择: ");

char choice;

scanf("%c", &choice);

getchar();

switch (choice)

{

case '1':

{

char bufBUF_SIZE={0};

char temp500;

printf("请输入要发送的内容: ");

scanf("%s", temp);

getchar();

snprintf(buf, sizeof(buf), "%c%s", GROUP_SEND, temp);

send(fd, buf, strlen(buf), 0);

break;

}

case '2':

{

char bufBUF_SIZE = {0};

char temp500;

printf("请输入要发送的内容: ");

scanf("%s", temp);

getchar();

printf("请输入要发送的对象的ip ");

char ip20 = {0};

scanf("%s", ip);

getchar();

snprintf(buf, sizeof(buf), "%c:%s:%s", SINGLE_SEND,ip, temp);

send(fd, buf, strlen(buf), 0);

break;

}

case '3':

{

close(fd);

exit(0);

}

default:

{

printf("输入错误\n");

break;

}

}

}

}

#include "command.h"

#include <stdio.h>

#include <stdlib.h>

#include <sys/socket.h>

#include <arpa/inet.h>

#include <string.h>

#include <unistd.h>

#include <wait.h>

#include "menuFunctions.h"

int main()

{

int fd;

fd=socket(AF_INET,SOCK_STREAM,0);

if(fd==-1)

{

perror("socket failed");

exit(-1);

}

struct sockaddr_in addr;

addr.sin_family=AF_INET;

addr.sin_port=htons(9000);

addr.sin_addr.s_addr=inet_addr("192.168.2.160");

if(connect(fd,(struct sockaddr*)&addr,sizeof(addr))==-1)

{

perror("connect failed");

exit(-1);

}

pid_t pid=fork();

if(pid==-1)

{

perror("fork failed");

exit(-1);

}

else if(pid==0)

{

sleep(15);

while(1)

{

char bufBUF_SIZE;

int len=read(fd,buf,sizeof(buf));

if(len==-1)

{

perror("read failed");

exit(-1);

}

else if(len==0)

{

printf("服务器已关闭\n");

exit(0);

}

else

{

printf("%s\n",buf);

}

}

}

else

{

menuForLoginAndRegister(fd);

wait(NULL);

}

}

相关推荐
阳光九叶草LXGZXJ3 小时前
达梦数据库-报错-15-列【XXX】长度超出定义
linux·运维·数据库·sql·学习
奔跑的大白啊4 小时前
多容器共享目录权限踩坑记
linux·ubuntu·共享目录·linux权限·docker 容器化部署
正在走向自律6 小时前
AI数据分析与可视化:从基础到应用实践
服务器·人工智能·python·机器学习·数据分析·pandas
OnlineProxy6 小时前
亚马逊多账号运营:如何在规避“关联封号”风险的同时实现电商规模化扩张
服务器·数据库·redis
盟接之桥6 小时前
当大模型遇见线束制造:不是通用AI,而是行业AI
大数据·网络·人工智能·安全·制造
Android系统攻城狮7 小时前
Linux Gstreamer深度解析之gst_audio_encoder_set_frame_max调用流程与实战(六十一)
android·linux·运维·音视频·gstreamer音视频·音视频进阶·gstreamer音视频进阶
H.莓飛7 小时前
【C++】命名空间、缺省参数、函数重载与引用
linux·开发语言·c++·visual studio
91刘仁德8 小时前
IP协议详解:从IP协议头到网段划分、路由与NAT
linux·服务器·网络·网络协议·tcp/ip
辻弋2018 小时前
五年前的旅行视频糊成马赛克?Video2X用Real-ESRGAN逐帧重建细节,但只支持Windows、集显用户建议直接放弃
服务器·数据库·windows·游戏引擎·电脑
硅基手札8 小时前
【Linux内核专栏 14】网络协议栈
linux·运维·网络协议