我用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 +的新手,如果有人理解代码,请帮助我。 三江源
答案 0 :(得分:1)
问题不是与gtk +有关,而是与缓冲区有关,如果您在消息框中获得了超过1024个字符(由服务器端代码定义),或者输入了多次填满所有1024个字符后,服务器端代码将从接收系统调用返回并执行后一个代码