尝试使用队列来处理服务器上的客户端消息[C]

时间:2016-06-01 09:41:46

标签: c server queue

我试图在c中编写一个服务器,允许连接的客户端相互发送消息。我尝试通过接收消息,将其放在队列上并让处理服务器 - 客户端通信(函数dostuff)的进程在用户名与消息匹配时传递该消息。

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

/******Struct msg*********/
typedef struct msg
{
    char dest  [64]; 
    char origin[64];  
    char text  [256]; 
}msg;
/*********Queue*********/
/*Queue - Linked List implementation*/
#include<stdio.h>
#include<stdlib.h>
struct Node {
    msg *data;
    struct Node* next;
};
struct Node* front = NULL;
struct Node* rear = NULL;
void Enqueue(msg *x) {
    struct Node* temp = 
        (struct Node*)malloc(sizeof(struct Node));
    temp->data =x; 
    temp->next = NULL;
    if(front == NULL && rear == NULL){
        front = rear = temp;
        return;
    }
    rear->next = temp;
    rear = temp;
}
void Dequeue() {
    struct Node* temp = front;
    if(front == NULL) {
        printf("Queue is Empty\n");
        return;
    }
    if(front == rear) {
        front = rear = NULL;
    }
    else {
        front = front->next;
    }
    free(temp);
}
msg *Front() {
    if(front == NULL) {
        return 0;
    }
    return front->data;
}
void error(const char *msg)
{
    perror(msg);
    exit(1);
}

int interpret(char *line, char username[])
{
    //printf("Ready to interpret: %s\n",line);

    /*  
    char *command, *arg1 , *arg2,l[64];
    msg *message;
    strcpy(l,line);
    command = strtok(l," ");

    if(strcmp(command, "/tell") == 0)
    {
        printf("The command was vaid!\n");//chegou aqui
        printf("Ready to interpret: %s\n",l);
        arg1 = strtok(NULL," ");
        printf("I got this far!");
        arg2 = l + strlen(command) + strlen(arg1) + 2; //somamos dois por causa dos espaços

        message = (msg*)malloc(sizeof(msg));

        //printf("I got this far!"); nao está a chegar aqui

        strcmp(message->dest, arg1);
        strcmp(message->origin, username);
        strcmp(message->text, arg2);
        Enqueue(message);
        printf("(%s -> %s) -%s- was placed on the queue",message->origin,message->dest,message->text);
    }
    else
    {
        printf("comando inválido");
    }

    */
        //this is temporary because there is an error with the code above which made the message not be correct
        msg *message;
        message = (msg*)malloc(sizeof(msg));

        strcmp(message->dest, "dest");
        strcmp(message->origin, "origin");
        strcmp(message->text, "blahblahblah");
        Enqueue(message);

    return 1;
}
void dostuff (int sock, char username[])
{
    int n, pid;
    char buffer[256], dest[64]; 
    pid = fork();
    while(1)
    {
        if(pid > 0)
        {
            bzero(buffer,256);
            n = read(sock,buffer,255);

            if (n < 0) error("ERROR reading from socket");

            printf("Here is the full message: %s\n",buffer);

            //n = write(sock,"I got your message!\n",18);
            //if (n < 0) error("ERROR writing to socket");

            interpret(buffer, username);
        }
        else
        {
            sleep(1); 
            if(Front() != NULL)
            {
                strcpy(dest, Front()->dest);
                if(strcmp(dest, username) == 0)
                {
                    strcpy(buffer, Front()->text);
                    Dequeue();
                    n = write(sock,buffer,strlen(buffer));
                    if (n < 0) error("ERROR writing to socket");
                }
            }
        }   
    }
}
int main(int argc, char *argv[])
{
     int sockfd, newsockfd, portno, pid , f;
     int userCount;                                                       
     socklen_t clilen;

     struct sockaddr_in serv_addr, cli_addr;                                

     if (argc < 2)
     {
         fprintf(stderr,"ERROR, no port provided\n");
         exit(1);
     }

     sockfd = socket(AF_INET, SOCK_STREAM, 0);                            
     if (sockfd < 0) 
        error("ERROR opening socket");

     bzero((char *) &serv_addr, sizeof(serv_addr));                            

     portno = atoi(argv[1]); 

     serv_addr.sin_family = AF_INET;                                           
     serv_addr.sin_addr.s_addr = INADDR_ANY;                                   
     serv_addr.sin_port = htons(portno);                                      

     if (bind(sockfd, (struct sockaddr *) &serv_addr,
              sizeof(serv_addr)) < 0) 
              error("ERROR on binding");

     listen(sockfd,5);                                                        
     clilen = sizeof(cli_addr);

     userCount = 0;
     char dname[64];                                                          
     f = fork();

     while (1) 
     {
        if(f > 0)
        {
            newsockfd = accept(sockfd,(struct sockaddr *) &cli_addr, &clilen);  
            if (newsockfd < 0) error("ERROR on accept");

            userCount++;                                                        
            sprintf(dname, "%d", userCount);                                    

            pid = fork();
            if (pid < 0) error("ERROR on fork");  
            if (pid == 0)
            {
                close(sockfd);
                dostuff(newsockfd, dname);
                exit(0);
            }
            else close(newsockfd);

        }
    }

    close(sockfd);
    return 0;
}

问题似乎是这段代码应该从队列中删除项目:

if(Front() != NULL)
            {
                strcpy(dest, Front()->dest);
                if(strcmp(dest, username) == 0)
                {
                    strcpy(buffer, Front()->text);
                    Dequeue();
                    n = write(sock,buffer,strlen(buffer));
                    if (n < 0) error("ERROR writing to socket");
                }
            }

永远不会被运行。 我之前从未做过这样的事情,所以这种做法可能完全错了。如果有人可以向我解释我做错了什么,或者提出了不同的解决方案,那就太棒了。

2 个答案:

答案 0 :(得分:0)

您误解了fork()之后管理全局变量的方式。

他们没有被分享;进程可以修改自己的变量副本。这些修改不会通知其他孩子/父母。

因此,您尝试使用Enqueue进行更改front指针的本地副本,但前指针的其他子副本不会更新。

将代码降至最低:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

/******Struct msg*********/
typedef struct msg
{
    char dest  [64];
    char origin[64];
    char text  [256];
}msg;
/*********Queue*********/
/*Queue - Linked List implementation*/
#include<stdio.h>
#include<stdlib.h>
struct Node {
    msg *data;
    struct Node* next;
};
struct Node* front = NULL;
struct Node* rear = NULL;

void Enqueue(msg *x)
{
    struct Node* temp = malloc(sizeof(struct Node));

    temp->data =x;
    temp->next = NULL;

    if(front == NULL && rear == NULL)
    {
        front = rear = temp;
        printf("front: %p\n", (void *)(front));
        printf("rear: %p\n" , (void *)(rear));
        printf("temp: %p\n" , (void *)(temp));
        return;
    }

    rear->next = temp;
    rear = temp;
}

void Dequeue(void) {
    struct Node* temp = front;
    if(front == NULL) {
        printf("Queue is Empty\n");
        return;
    }
    if(front == rear) {
        front = rear = NULL;
    }
    else {
        front = front->next;
    }
    free(temp);
}
msg *Front(void) {
    if(front == NULL) {
        return 0;
    }
    return front->data;
}
void error(const char *msg)
{
    perror(msg);
    exit(1);
}

int interpret(void)
{

    //this is temporary because there is an error with the code above which made the message not be correct
    msg *message;
    message = (msg*)malloc(sizeof(msg));

    strcpy(message->dest, "dest");
    strcpy(message->origin, "origin");
    strcpy(message->text, "blahblahblah");
    Enqueue(message);

    return 1;
}

void dostuff (void)
{
    pid_t pid;

    pid = fork();

    if(pid > 0)
    {
        interpret();
    }
    else
    {
        sleep(1);
        printf("\nfront: %p\n", (void *)(front));
    }
}
int main(int argc, char *argv[])
{
    pid_t f, pid;

    f = fork();

    if(f > 0)
    {
        pid = fork();

        if (pid < 0) 
           error("ERROR on fork");

        if (pid == 0)
        {
            dostuff();
        }
    }

    return 0;
}

输出

front: 0x18371a0
rear: 0x18371a0
temp: 0x18371a0
root@mypc:~$
front: (nil)

答案 1 :(得分:0)

使用线程而不是fork。 开始两个线程。一个用于倾听,一个用于回答。

Fork创建了新的操作系统进程,它共享相同的代码,但数据段不同。所以你在一个过程中改变的东西将不会出现在另一个过程中。