Socket Server Multi-Prozess, um Gruppenchat zu erreichen

Lehrvideo

Aufgabe des Clients: Senden Sie Daten an den Server und können Sie die vom Server empfangenen Informationen empfangen

Serverfunktion: Kann die von mehreren Clients gesendeten Daten empfangen und an alle Clients senden, dh die Funktion des Gruppenchats erfüllen. Der Server kann auch als Übertragungsstation für die Informationsspeicherung verwendet werden

Client-Code

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
using namespace std;

#include <errno.h>

#define PUB_MSG_TYPE 256

#define ERR_EXIT(m) \
    do{\
        perror(m);\
        _exit(1); \
    } while (0)


int main()
{
    int ret = 0;
    int socket_fd = socket(AF_INET, SOCK_STREAM, 0);//创建socket
    if (socket_fd == 1)
        ERR_EXIT("socket");
    //绑定ip和端口
    struct  sockaddr_in ser_addr;
    ser_addr.sin_family = AF_INET;
    ser_addr.sin_port = htons(8097);
    inet_aton("192.168.1.9", &ser_addr.sin_addr);

    ret = connect(socket_fd, (struct sockaddr*)&ser_addr, sizeof(ser_addr));
    if (ret == -1)
        ERR_EXIT("connect");
    cout << "connect success" << endl;

    pid_t  pid = fork();
    if (pid == 0)
    {
        //子进程进行读取数据
        char rbuf[1024] = { 0 };
        while (1)
        {
            ret = read(socket_fd, rbuf, sizeof(rbuf));
            if (ret == 0)
            {
                cout << "server is off" << endl;
                break;
            }
            cout << "read:" << rbuf << endl;
            memset(rbuf, 0x0, sizeof(rbuf));
        }
        exit(EXIT_SUCCESS);
    }

    //父进程负责从键盘获取数据输入  发送给服务器
    char sbuf[1024] = { 0 };
    while (fgets(sbuf, sizeof(sbuf), stdin) != 0)//stdin标准输入
    {
        write(socket_fd, sbuf, sizeof(sbuf));
        memset(sbuf, 0x0, sizeof(sbuf));
    }
    return 0;
}

Pseudocode des Servers:

  • Der untergeordnete Prozess liest Informationen in buf
  • buf schreibt in die Nachrichtenwarteschlange und sendet ein Signal an den übergeordneten Prozess
  • Wenn der übergeordnete Prozess das Signal empfängt, geht er in die Nachrichtenwarteschlange, um die Daten abzurufen, durchläuft das Dateideskriptor-Array des Clients und schreibt zirkulär in den verbundenen Client

 

Servercode:

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <unistd.h>
#include <string.h>
#include <vector>

#include <sys/ipc.h>
#include <sys/msg.h>
#include <signal.h>
using namespace std;

#include <errno.h>

#define PUB_MSG_TYPE 256

#define ERR_EXIT(m) \
    do{\
        perror(m);\
        exit(1); \
    } while (0)

vector<int>  vfds;//存放所有的客户端的文件描述符
int msgid;//消息队列的id

//消息结构体
typedef struct msg_buf {
    long mtype;// message type, must be > 0
    char mtest[PUB_MSG_TYPE];//message data
    //void* mtest;
}MSG_T;
#define CHAT_MSG_TYPE 10

MSG_T rcvMsg;
vector<int>::iterator  it;
//信号动作
void handler(int num)
{
    cout << "num = " << num << endl;
    //1.从消息对列中取出消息
    msgrcv(msgid, &rcvMsg, sizeof(MSG_T), CHAT_MSG_TYPE, 0);
    cout << "recv:" << rcvMsg.mtest << endl;
    //2.群发
    for (it = vfds.begin();it != vfds.end();it++)
    {
        write(*it, rcvMsg.mtest, sizeof(rcvMsg.mtest));
    }
}
//服务器
int main()
{
    int socket_fd = socket(AF_INET, SOCK_STREAM, 0);//创建一个TCPsocket
    if (socket_fd == 1)
        ERR_EXIT("socket");
    //绑定ip和端口
    struct  sockaddr_in ser_add;
    ser_add.sin_family = AF_INET;
    ser_add.sin_port = htons(8097);//端口号
    ser_add.sin_addr.s_addr = htonl(INADDR_ANY);

    //地址可重复使用
    int on = 1;
    setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

    int ret = bind(socket_fd, (struct sockaddr*)&ser_add, sizeof(ser_add));
    if (ret == -1)
        ERR_EXIT("bind");

    ret = listen(socket_fd, SOMAXCONN);//监听数据存放队列中
    if (ret == -1)
        ERR_EXIT("listen");

    struct sockaddr_in cli_add;
    socklen_t add_len = sizeof(cli_add);
    //int add_len = sizeof(cli_add);
    cout << "wait for client..." << endl;

    //安装信号
    msgid = msgget(5678, 0666 | IPC_CREAT);
    signal(SIGUSR2, handler);
    while (1)
    {
        int  con_fd = accept(socket_fd, (struct sockaddr*)&cli_add, &add_len);
        vfds.push_back(con_fd);//存放连接的客户端的文件描述符
        cout << "someone on line..." << endl;
        cout << "father  pid =  " << getpid() << endl;
        pid_t pid = fork();
        if (pid == 0)
        {
            char buf[1024] = { 0 };
            while (1)
            {
                ret = read(con_fd, buf, sizeof(buf));
                if (ret == 0)
                {
                    cout << "client is offline" << endl;
                    break;
                }
                cout << "buf=" << buf << endl;
                //1.把消息写入消息队列
                MSG_T msg;
                msg.mtype = CHAT_MSG_TYPE;
                strcpy(msg.mtest, buf);
                msgsnd(msgid, &msg, sizeof(MSG_T),0);//0非阻塞
                //2.发信号通知父进程去取数据 
                kill(getppid(), SIGUSR2);
                //write(con_fd, buf, sizeof(buf));
                memset(buf, 0, sizeof(buf));
            }
            exit(EXIT_SUCCESS);
        }
    } 


    return 0;
}

 

Effekt erzielen

Ich denke du magst

Origin blog.csdn.net/m0_49036370/article/details/113860979
Empfohlen
Rangfolge