Step by step to create a chat program 1- use of processes and shared memory to create simple chat program

    Linux recently learned knowledge about inter-process communication, so decided to use processes and shared memory, and to create a simple chat program in accordance with the producer-consumer model. Following is a brief talk about the idea of the program.
    The first is the server program, the server creates two processes, process 1 is responsible for receiving the message transmitted from the client, and stored. 1 process 2 process is responsible for reading the news access. Here the producers and consumers to use programming model, and declare the message deposit structure below.

struct message
{
    int target_id;
    char buf[100];
};

//消息仓库
struct canku
{
    struct message recv_message[10];
    int read_pos,write_pos;
}messages;

 

 

You can see, I am here to enforce the message warehouses can only store up to 10 messages (in fact, can only store nine, and producer-consumer model related).
    Producer and consumer model: read_pos and after use, respectively write_pos marking position reading and writing, each time reading and writing, increments write_pos read_pos or 1, or when read_pos write_pos reaches the end of the array, it will be reset to zero, similar to a circular linked list, but this will be a problem: how to determine whether the list is empty, or if the list has been filled?
    Using read_pos (reading position messages) and write_pos (write location message) to determine whether the message repository is empty and full. Message warehouse when empty and full two states, read_pos and write_pos are equal, so obviously does not meet our requirements. Therefore, an empty message bit, using the following conditions to determine if it is full or empty.

  1. The message is empty
    if((messages_ptr->read_pos)%10==messages_ptr->write_pos)
    {
        //printf("buff is empty\n");
        shmdt(messages_ptr);
        continue;
    }

     

    I.e., when the value is equal read_pos and write_pos, it indicates an empty state message repository.
  2. Full message warehouse
    if((messages_ptr->write_pos+1)%10==messages_ptr->read_pos)
    {
        shmdt(messages_ptr);
        continue;
    }

     

     
    That is, when a position of the next write_pos read_pos, warehouse is full at this time. It can be seen that the message can not store data space is wasted. This method solves the problem of how to determine the status messages and empty warehouses full state, but wasted a message space.

    We also by means of shared memory, message repository will be mapped to the shared memory, so that the processes 1 and 2 can access the message repository.

    The client is simpler than the service side, I created a sub-process is used to read the other server forwards a message sent by the client. The parent process is used to read the client input, sends a message to the server.

    Code is as follows:
  the server:

  

#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <errno.h>

#define MAX_LISTEN 10

struct message
{
    int target_id;
    char buf[100];
};

//消息仓库
struct canku
{
    struct message recv_message[10];
    int read_pos,write_pos;
}messages;

//messages初始化
void init()
{
    messages.read_pos=0;
    messages.write_pos=0;
}

//messages销毁
void finish()
{
    messages.read_pos=0;
    messages.write_pos=0;
}

int sd;

int main()
{
    init();
    struct sockaddr_in server_ip,customer_ip;
    int err;
    
    sd=socket(AF_INET,SOCK_STREAM,0);
    if(sd==-1)
    {
        printf("socket failed\n");
        close(sd);
        return -1;
    }

    //server_ip初始化
    server_ip.sin_family=AF_INET;
    server_ip.sin_port=htons(5678);
    server_ip.sin_addr.s_addr=htonl(INADDR_ANY);
    memset(server_ip.sin_zero,0,8);

    err=bind(sd,(struct sockaddr *)(&server_ip),sizeof(struct sockaddr));
    if(err==-1)
    {
        printf("bind failed\n");
        close(sd);
        return -1;
    }

    err=listen(sd,MAX_LISTEN);
    if(err==-1)
    {
        printf("listen failed\n");
        close(sd);
        return -1;
    }

    int length=sizeof(customer_ip);

    //初始化共享变量,大小等于canku by luke
    int shmid=shmget(IPC_PRIVATE,sizeof(struct canku),IPC_CREAT|0777);
    if(shmid<0)
    {
        printf("shmget failed\n");
        return -1;;
    }

    struct canku * messages_ptr=&messages;

    while(1)
    {
        int temp_cd=accept(sd,(struct sockaddr *)(&customer_ip),&length);
        if(temp_cd==-1)
        {
            printf("accept failed,ereno: %d\n",temp_cd);
            close(sd);
            return -1;
        }

        printf("user %d online\n",temp_cd);

        
        pid_t pid=fork();
        if(pid==0)//子进程 by luke
        {
            while(1)
            {
                messages_ptr=shmat(shmid,NULL,0);
                if((messages_ptr->write_pos+1)%10==messages_ptr->read_pos)
                {
                   shmdt(messages_ptr);
                   continue;
                }

                struct message temp_message;
                err=recv(temp_cd,&temp_message,sizeof(struct message),0);
                //err=read(temp_cd,&(recv_message[count-1]),sizeof(struct message));
                if(err!=-1)
                {
                    messages_ptr->recv_message[messages_ptr->write_pos].target_id=temp_message.target_id;
                    strcpy(messages_ptr->recv_message[messages_ptr->write_pos].buf,temp_message.buf);
                    printf("recv: read_pos: %d, write_pos: %d, target_id: %d, buf: %s\n",messages_ptr->read_pos,messages_ptr->write_pos+1,messages_ptr->recv_message[messages_ptr->write_pos].target_id,messages_ptr->recv_message[messages_ptr->write_pos].buf);
                    messages_ptr->write_pos++;
                    if(messages_ptr->write_pos==9)
                        messages_ptr->write_pos=0;
                } 

                Shmdt (messages_ptr); 
            } 
        } 
        
        // prevent the main thread while live, can not accept the new connection request. 
        PID1 = pid_t the fork ();
         IF (PID1 == 0 ) 
        { 
            the while ( . 1 ) 
            { 
                messages_ptr = the shmat (the shmid, NULL, 0 );
                IF ((messages_ptr-> read_pos)% 10 == messages_ptr-> write_pos) 
               { 
                   / / the printf ( "IS BUFF empty \ n-"); 
                   shmdt (messages_ptr);
                    Continue ; 
               } 
                
                //strcpy(messages_ptr->recv_message[messages_ptr->read_pos].buf,"hello");
                err=send(messages_ptr->recv_message[messages_ptr->read_pos].target_id,messages_ptr->recv_message[messages_ptr->read_pos].buf,100,0);
                if(err==-1)
                {
                    //printf("send failed\n");
                }
                else
                {
                    printf("send: read_pos: %d, write_pos: %d ,message.target_id: %d, message.buf: %s\n",messages_ptr->read_pos+1,messages_ptr->write_pos,messages_ptr->recv_message[messages_ptr->read_pos].target_id,messages_ptr->recv_message[messages_ptr->read_pos].buf);
                    messages_ptr->read_pos++;
                    if(messages_ptr->read_pos==9)
                        messages_ptr->read_pos=0;
                }
                shmdt(messages_ptr);
            }
        }
    }

    close(sd);
    shmctl(shmid,IPC_RMID,NULL);
    finish();
    return 0;
}

Client:

#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

struct message
{
    int target_id;
    char buf[100];
};

int sd;
struct message send_message;

void * read_message(void * argv)
{
    while(1)
    {
        //读服务器发来的消息
        char revBuf[100];
        read(sd,revBuf,100);
        printf("recevice from server: %s",revBuf);
    }
}

void * write_message(void * argv)
{
    while(1)
    {
        printf("input message: \n");
        memset(send_message.buf,0,128);
        send_message.target_id=-1;
        scanf("%d %s",&send_message.target_id,send_message.buf);

        write(sd,&send_message,sizeof(send_message));
        sleep(3);
    }
}

int main()
{
    struct sockaddr_in server_ip,customer_ip;
    int err;

    sd=socket(AF_INET,SOCK_STREAM,0);
    if(sd==-1)
    {
        printf("socket failed\n");
        close(sd);
        return -1;
    }

    //server_ip初始化
    server_ip.sin_family=AF_INET;
    server_ip.sin_port=htons(5678);
    server_ip.sin_addr.s_addr=htonl(INADDR_ANY);
    //err=inet_aton("115.157.201.179",&server_ip.sin_addr.s_addr);
    memset(server_ip.sin_zero,0,8);

    err=connect(sd,(struct sockaddr *)(&server_ip),sizeof(server_ip));
    if(err==-1)
    {
        printf("connect failed\n");
        close(sd);
        return -1;
    }

    pid_t pid=fork();
    if(pid==0)
    {
        while(1)
        {
            //读服务器发来的消息
            //printf("read message: \n");
            char revBuf[100];
            recv(sd,revBuf,100,0);
            //read(sd,revBuf,100);
            printf("recevice from server: %s\n",revBuf);
        }
    }
    while(1)
    {
        printf("input message: \n");
        memset(send_message.buf,0,128);
        send_message.target_id=-1;
        scanf("%d %s",&send_message.target_id,send_message.buf);

        if(send_message.target_id!=-1&&(strcmp(send_message.buf,"")!=0))
        {

            err=send(sd,&send_message,sizeof(send_message),0);
            if(err==-1)
            {
                printf("send failed\n");
            }
            //write(sd,&send_message,sizeof(send_message));

            send_message.target_id=-1;
            memset(send_message.buf,0,sizeof(send_message.buf));
        }

        sleep(3);
    }

    close(sd);
    return 0;
}

 

Guess you like

Origin www.cnblogs.com/JsonZhangAA/p/11904768.html
Recommended