服务器未通过GTK +中的客户端GUI收到短信

时间:2015-10-24 20:46:08

标签: c linux pthreads client-server gtk2

我用C语言编写了一个简单的聊天程序,在Linux上使用TCP Socket(客户端和服务器),它在终端上完美地发送和接收消息。然后我尝试使用GTK +创建一个GUI,其上有一个GLabel,一个Textfield(用户将从中写入其消息)和一个提交按钮。但是当我在文本字段中键入任何文本后单击“发送”按钮时,只有在客户端程序关闭后,服务器才会接收文本。当我关闭客户端程序时,服务器会打印所有文本消息。我不明白它是否是线程调度的问题或其他 这是我的代码:

server.c:

#include<arpa/inet.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>

#define MAX_CLIENTS 100

static unsigned int cli_count = 0;
static int uid = 10;

typedef struct 
{
    struct sockaddr_in addr;    
    int connfd;         
    int uid;            
    char name[32];          
}client_t;

client_t *clients[MAX_CLIENTS];

void queue_add(client_t *cl)
{
    int i;
    for(i=0;i<MAX_CLIENTS;i++)
    {
        if(!clients[i])
        {
            clients[i] = cl;
            return;
        }
    }
}

void queue_delete(int uid)
{
    int i;
    for(i=0;i<MAX_CLIENTS;i++)
    {
        if(clients[i])
        {
            if(clients[i]->uid == uid)
            {
                clients[i] = NULL;
                return;
            }
        }
    }
}
void print_client_addr(struct sockaddr_in addr)
{
    printf("%d.%d.%d.%d",
        addr.sin_addr.s_addr & 0xFF,
        (addr.sin_addr.s_addr & 0xFF00)>>8,
        (addr.sin_addr.s_addr & 0xFF0000)>>16,
        (addr.sin_addr.s_addr & 0xFF000000)>>24);
}

void *hanle_client(void *arg)
{
    char buff_in[1024];
    int rlen;

    cli_count++;
    client_t *cli = (client_t *)arg;

    printf("<<ACCEPT ");
    print_client_addr(cli->addr);
    printf(" REFERENCED BY %d\n", cli->uid)    

    while((rlen = recv(cli->connfd, buff_in, sizeof(buff_in)-1,0)) > 0)
    {
            buff_in[rlen] = '\0';
            printf("[%s] %s",cli->name,buff_in);
    }
    close(cli->connfd);

    /* Delete client from queue and yeild thread */
    queue_delete(cli->uid);
    printf("<<LEAVE ");
    print_client_addr(cli->addr);
    printf(" REFERENCED BY %d\n", cli->uid);
    free(cli);
    cli_count--;
    pthread_detach(pthread_self());

    return NULL;
}

int main(int argc, char *argv[])
{
    int listenfd = 0, connfd = 0, portno;
    struct sockaddr_in serv_addr;
    struct sockaddr_in cli_addr;
    pthread_t tid;
    if (argc < 2) {
         printf("ERROR, no port provided\n");
         exit(1);
     }


    //Create socket
    listenfd= socket(AF_INET , SOCK_STREAM , 0);
    if (listenfd == -1)
    {
        printf("Could not create socket");
    }
    bzero((char *) &serv_addr, sizeof(serv_addr));
    portno = atoi(argv[1]);
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(portno);

    /* Bind */
    if(bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
    {
        perror("Socket binding failed");
        return 1;
    }

    /* Listen */
    if(listen(listenfd, 10) < 0){
        perror("Socket listening failed");
        return 1;
    }

    printf("<[SERVER STARTED]>\n");
    socklen_t clilen = sizeof(cli_addr);

    /* Accept clients */
    while( (connfd = accept(listenfd, (struct sockaddr *)&cli_addr, (socklen_t*)&clilen)))
    {

        /* Check if max clients is reached */
        if((cli_count+1) == MAX_CLIENTS)
        {
            printf("<<MAX CLIENTS REACHED\n");
            printf("<<REJECT ");
            print_client_addr(cli_addr);
            printf("\n");
            close(connfd);
            continue;
        }

        /* Client settings */
        client_t *cli = (client_t *)malloc(sizeof(client_t));
        cli->addr = cli_addr;
        cli->connfd = connfd;
        cli->uid = uid++;
        sprintf(cli->name, "%d", cli->uid);

        /* Add client to the queue and fork thread */
        queue_add(cli);
        if(pthread_create(&tid, NULL, &hanle_client, (void*)cli)==0);
        {
            printf("Handler assigned");
        }

        /* Reduce CPU usage */
        sleep(1);
    }
}

client.c

#include<stdio.h> //printf
#include<string.h>    //strlen  
#include<arpa/inet.h> //inet_addr
#include<netdb.h>
#include<stdlib.>
#include<gtk/gtk.h>

int sockfd;
static void setUpGUI(int arc, char *arv[]);
int main(int argc , char *argv[])
{
    int  portno ;
    struct sockaddr_in serv_addr;
    struct hostent *server;
    char server_reply[2000];
    if (argc <3) 
    {
      fprintf(stderr,"usage %s hostname port\n", argv[0]);
      exit(1);
    }
   portno = atoi(argv[2]);

    //Create socket
    sockfd = socket(AF_INET, SOCK_STREAM, 0);

   if (sockfd < 0)
   {
      perror("ERROR opening socket");
      exit(1);
   }
   server = gethostbyname(argv[1]);

   if (server == NULL) {
      fprintf(stderr,"ERROR, no such host\n");
      exit(1);
   }

   bzero((char *) &serv_addr, sizeof(serv_addr));
   serv_addr.sin_family = AF_INET;
   bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
   serv_addr.sin_port = htons(portno);



    //Connect to remote server
   if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
   {
      perror("ERROR connecting");
      exit(1);
   }

    puts("Connected\n");


    setUpGUI(argc,argv);
    gtk_main();


    //keep communicating with server
    close(sockfd);
    return 0;
}
static void callback( GtkWidget *widget, GtkWidget *entry )
{
    const gchar *entry_text;
    entry_text = gtk_entry_get_text (GTK_ENTRY (entry));
    g_free(entry_text);

    printf ("Entry contents: %s\n", entry_text);
    if(send(sockfd , entry_text , strlen(entry_text),0) < 0)
        {
            puts("Send failed");
        }
    gtk_entry_set_text(GTK_ENTRY(entry), "");

}

static void destroy(GtkWidget *widget, gpointer data)
{
    gtk_main_quit ();
}

static void initialize_window(GtkWidget* window)
{
    gtk_window_set_title(GTK_WINDOW(window),"My Window"); //Set window title
    gtk_window_set_default_size (GTK_WINDOW (window), 400, 200); //Set default size for the window
    gtk_container_set_border_width (GTK_CONTAINER (window), 10);
    g_signal_connect (window, "destroy", G_CALLBACK (destroy), NULL); //End application when close button clicked
}


static void setUpGUI(int arc , char *arv[])
{
    GtkWidget *window,*box1,*box2,*scrolledwindow,*textArea,*label1,*label2,*entry,*button;
    GtkEntryBuffer* entry_buffer= gtk_entry_buffer_new(NULL, 0);
    gtk_init(&arc, &arv);

    //Create the main window
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    initialize_window(window);


    //Create new box
    box1 = gtk_vbox_new (FALSE, 0);
    gtk_container_add (GTK_CONTAINER (window), box1);

    /* create a new label Message. */
    label1 = gtk_label_new ("Message:" );
    gtk_misc_set_alignment (GTK_MISC (label1),0,0);
    gtk_box_pack_start(GTK_BOX (box1), label1, FALSE, FALSE, 0);
    gtk_widget_show(label1);

    //Create new TextView
    textArea = gtk_text_view_new();
    scrolledwindow = gtk_scrolled_window_new(NULL, NULL);
    gtk_container_add(GTK_CONTAINER(scrolledwindow), textArea);
    gtk_text_view_set_editable(GTK_TEXT_VIEW(textArea),FALSE);
    gtk_box_pack_start(GTK_BOX (box1), scrolledwindow, TRUE, TRUE, 0);
    gtk_widget_show(textArea);
    gtk_widget_show(scrolledwindow);

    /* create a new label Enter message. */
    label2 = gtk_label_new ("Enter message:" );
    gtk_misc_set_alignment (GTK_MISC (label2), 0, 0);
    gtk_box_pack_start(GTK_BOX (box1), label2, FALSE, FALSE, 0);
    gtk_widget_show(label2);

    box2 = gtk_hbox_new (FALSE, 0);
    gtk_box_pack_start(GTK_BOX (box1), box2, FALSE, FALSE, 0);


    //create a text box
    entry = gtk_entry_new_with_buffer(entry_buffer);
    g_signal_connect (entry, "activate",G_CALLBACK (callback),entry);
    gtk_box_pack_start(GTK_BOX (box2), entry, FALSE, FALSE, 0);
    gtk_widget_show(entry);



    //Create a new button
    button = gtk_button_new_with_label ("Send");
    g_signal_connect (button, "clicked",G_CALLBACK (callback), entry);
    gtk_box_pack_start(GTK_BOX (box2), button, FALSE, FALSE, 0);
    gtk_widget_show(button);

    gtk_widget_show(box2);

    gtk_widget_show (box1);
    gtk_widget_show (window);       
}

我是GTK +的新手,如果有人理解代码,请帮助我。 三江源

1 个答案:

答案 0 :(得分:1)

问题不是与gtk +有关,而是与缓冲区有关,如果您在消息框中获得了超过1024个字符(由服务器端代码定义),或者输入了多次填满所有1024个字符后,服务器端代码将从接收系统调用返回并执行后一个代码