GTK+浅谈之十三网络编程
来源:互联网 发布:php sleep 函数执行 编辑:程序博客网 时间:2024/05/16 06:31
一、简介
网络编程是Linux功能的强项,Gtk+2.0结合Linux系统的网络编程编写服务器和客户端。
二、详解
1、简单的ECHO程序
套接字编程是服务应用程序开发的关键和核心,GLIB在底层提供了对它们的支持。在此创建一个ECHO服务器,把用户发给它的数据原本地返回给客户端。(1)ECHO服务器
服务器的运行过程:
代码echo_server.c:
#include <glib.h>#include <stdio.h>#include <fcntl.h>#include <sys/socket.h>#include <sys/types.h>#include <sys/time.h>#include <unistd.h>#include <netdb.h>#include <netinet/in.h>#define OURPORT 8088void do_service(gint sd){ gchar buf[1024] = {0}; while (read(sd, buf, 1024) != -1) { write(sd, buf, 1024); }}int main(int argc, char *argv[]){ gint sd, newsd; struct sockaddr_in *sin; gint slen; sd = socket(AF_INET, SOCK_STREAM, 0); if (sd == -1) { g_print("create socket error!\n"); return -1; } sin = g_new(struct sockaddr_in, 1); sin->sin_family = AF_INET; sin->sin_port = OURPORT; slen = sizeof(struct sockaddr_in); if (bind(sd, (struct sockaddr*)sin, slen) < 0) { g_print("bind error!\n"); return -1; } if (listen(sd, 8) < 0) { g_print("listen error!\n"); return -1; } for(;;) { newsd = accept(sd, (struct sockaddr*)sin, &slen); if (newsd == -1) { g_print("accept error!\n"); break; } switch (fork()) { case 0: do_service(newsd); break; case -1: g_print("fork error!\n"); break; } } close(sd); g_free(sin); return TRUE;}编译运行:
gcc -o echo_server echo_server.c `pkg-config --cflags --libs glib-2.0`运行后,客户端通过端口8088连接。
(2)ECHO客户端
代码echo_client.c:
#include <gtk/gtk.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#define OURPORT 8088gint sd;struct sockaddr_in s_in;gchar username[64];gchar buf[1024];gchar get_buf[1048];gboolean isconnected = FALSE;static GtkWidget *text;static GtkTextBuffer *buffer;static GtkWidget *message_entry;gboolean do_connect(void){ GtkTextIter iter; gint slen; sd = socket(AF_INET, SOCK_STREAM, 0); if (sd < 0) { gtk_text_buffer_get_end_iter(buffer, &iter); gtk_text_buffer_insert(buffer, &iter, "打开套接字时出错!\n", -1); return FALSE; } s_in.sin_family = AF_INET; s_in.sin_port = OURPORT; slen = sizeof(s_in); if (connect(sd, (struct sockaddr*)&s_in, slen) < 0) { gtk_text_buffer_get_end_iter(buffer, &iter); gtk_text_buffer_insert(buffer, &iter, "连接服务器时出错!\n", -1); return FALSE; } else { gtk_text_buffer_get_end_iter(buffer, &iter); gtk_text_buffer_insert(buffer, &iter, username, -1); gtk_text_buffer_get_end_iter(buffer, &iter); gtk_text_buffer_insert(buffer, &iter, "成功与服务器连接...\n", -1); isconnected = TRUE; return TRUE; }}void on_send(GtkButton *button, gpointer data){ const char *message; GtkTextIter iter; if (isconnected == FALSE) return; message = gtk_entry_get_text(GTK_ENTRY(message_entry)); sprintf(buf, "%s\n", message); write(sd, buf, 1024); gtk_entry_set_text(GTK_ENTRY(message_entry), ""); read(sd, buf, 1024); sprintf(get_buf, "%s", buf); gtk_text_buffer_get_end_iter(buffer, &iter); gtk_text_buffer_insert(buffer, &iter, get_buf, -1);}void on_delete_event(GtkWidget *widget, GdkEvent *event, gpointer data){ close(sd); gtk_main_quit();}int main(int argc, char *argv[]){ GtkWidget *window; GtkWidget *vbox, *hbox, *button, *label, *view; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(on_delete_event), NULL); gtk_window_set_title(GTK_WINDOW(window), "ECHO客户端"); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_container_set_border_width(GTK_CONTAINER(window), 10); vbox = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(window), vbox); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5); label = gtk_label_new("来自服务器"); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5); view = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(view), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); text = gtk_text_view_new(); gtk_box_pack_start(GTK_BOX(vbox), view, TRUE, TRUE, 5); gtk_container_add(GTK_CONTAINER(view), text); buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5); label = gtk_label_new("输入信息:"); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5); message_entry = gtk_entry_new(); gtk_box_pack_start(GTK_BOX(hbox), message_entry, FALSE, FALSE, 5); button = gtk_button_new_with_label("发送"); gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 5); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(on_send), NULL); do_connect(); gtk_widget_show_all(window); gtk_main(); return TRUE;}编译运行:
gcc -o echo_client echo_client.c `pkg-config --cflags --libs gtk+-2.0`
2、多人聊天程序
服务器利用GLIB线程功能和Linux的网络编程功能向多用户同时发送数据。(1)多人聊天服务器
代码server.c:
#include <glib.h>#include <stdio.h>#include <fcntl.h>#include <signal.h>#include <sys/socket.h>#include <sys/types.h>#include <sys/time.h>#include <unistd.h>#include <netdb.h>#include <netinet/in.h>#define OURPORT 8088#define MAX_USERS 8struct _client{ gint sd; gboolean in_use; gchar name[64]; gchar buf[1024];};typedef struct _client client;client user[MAX_USERS];void do_service(gpointer id){ gint j; gchar tobuf[1024] = {0}; gint num = -1; while(num = read(user[GPOINTER_TO_INT(id)].sd, user[GPOINTER_TO_INT(id)].buf, 1024)) { if (num == -1 || num == 0) break; sprintf(tobuf, "%s:%s\n", user[GPOINTER_TO_INT(id)].name, user[GPOINTER_TO_INT(id)].buf); for(j = 0; j < MAX_USERS; j++) { if (user[j].in_use) { write(user[j].sd, tobuf, 1024); g_print("%s", tobuf); } } } user[GPOINTER_TO_INT(id)].in_use = FALSE; close(user[GPOINTER_TO_INT(id)].sd);}int main(int argc, char *argv[]){ gint sd, newsd; struct sockaddr_in *sin; gint slen; gint count = 0; gint flags; gchar buf[1024]; gchar tobuf[1024]; gint length, i, j; if (!g_thread_supported()) { g_thread_init(NULL); } else { g_print("thread not supported\n"); } sd = socket(AF_INET, SOCK_STREAM, 0); if (sd == -1) { g_print("create socket error!\n"); return -1; } sin = g_new(struct sockaddr_in, 1); sin->sin_family = AF_INET; sin->sin_port = OURPORT; slen = sizeof(struct sockaddr_in); if (bind(sd, (struct sockaddr*)sin, slen) < 0) { g_print("bind error!\n"); return -1; } if (listen(sd, 8) < 0) { g_print("listen error!\n"); return -1; } for (i = 0; i < MAX_USERS; i++) { user[i].in_use = FALSE; } flags = fcntl(sd, F_GETFL); fcntl(sd, F_SETFL, flags &~O_NDELAY); for(;;) { newsd = accept(sd, (struct sockaddr*)sin, (socklen_t *)&slen); if (newsd == -1) { g_print("accept error!\n"); break; } else { if (count >= MAX_USERS) { sprintf(buf, "用户数量过多服务器不能通讯。\n"); write(newsd, buf, 1024); close(newsd); } else { flags = fcntl(user[i].sd, F_GETFL); fcntl(user[i].sd, F_SETFL, O_NONBLOCK); user[count].sd = newsd; user[count].in_use = TRUE; read(newsd, user[count].name, 64); g_thread_create((GThreadFunc)do_service, (gpointer)count, TRUE, NULL); count++; } } } close(sd); g_free(sin);}编译运行:
gcc -o server server.c `pkg-config --cflags --libs glib-2.0 gthread-2.0`运行,等待客户端的连接。
(2)多人聊天客户端
代码client.c:
#include <gtk/gtk.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#define OURPORT 8088gint sd;struct sockaddr_in s_in;gchar username[64];gchar buf[1024];gchar get_buf[1048];gboolean isconnected = FALSE;static GtkWidget *text;static GtkTextBuffer *buffer;static GtkWidget *message_entry;static GtkWidget *name_entry;static GtkWidget *login_button;void get_message(){ GtkTextIter iter; gchar get_buf[1024]; gchar buf[1024]; gint num = -1; while(num = read(sd, buf, 1024)) { if (num == -1 || num == 0) break; sprintf(get_buf, "%s", buf); gdk_threads_enter(); gtk_text_buffer_get_end_iter(buffer, &iter); gtk_text_buffer_insert(buffer, &iter, get_buf, -1); gdk_threads_leave(); }}gboolean do_connect_run(){ GtkTextIter iter; gint slen; sd = socket(AF_INET, SOCK_STREAM, 0); if (sd < 0) { gtk_text_buffer_get_end_iter(buffer, &iter); gtk_text_buffer_insert(buffer, &iter, "打开套接字时出错!\n", -1); return FALSE; } s_in.sin_family = AF_INET; s_in.sin_port = OURPORT; slen = sizeof(s_in); if (connect(sd, (struct sockaddr*)&s_in, slen) < 0) { gtk_text_buffer_get_end_iter(buffer, &iter); gtk_text_buffer_insert(buffer, &iter, "连接服务器时出错!\n", -1); return FALSE; } else { gtk_text_buffer_get_end_iter(buffer, &iter); gtk_text_buffer_insert(buffer, &iter, username, -1); gtk_text_buffer_get_end_iter(buffer, &iter); gtk_text_buffer_insert(buffer, &iter, "成功与服务器连接...\n", -1); write(sd, username, 64); isconnected = TRUE; return TRUE; }}void on_destroy(GtkWidget *widget, GdkEvent *event, gpointer data){ sprintf(username, "guest"); if(do_connect_run() == TRUE) { gtk_widget_set_sensitive(login_button, FALSE); g_thread_create((GThreadFunc)get_message, NULL, FALSE, NULL); } gtk_widget_destroy(widget);}void on_button_clicked(GtkButton *button, gpointer data){ const gchar *name; name = gtk_entry_get_text(GTK_ENTRY(name_entry)); sprintf(username, "%s", name); if (do_connect_run()) { gtk_widget_set_sensitive(login_button, FALSE); g_thread_create((GThreadFunc)get_message, NULL, FALSE, NULL); } gtk_widget_destroy(GTK_WIDGET(data));}void create_win(){ GtkWidget *win, *vbox; GtkWidget *button; win = gtk_window_new(GTK_WINDOW_TOPLEVEL); g_signal_connect(G_OBJECT(win), "delete_event", G_CALLBACK(on_destroy), NULL); gtk_window_set_title(GTK_WINDOW(win), "输入用户名"); gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_CENTER); gtk_container_set_border_width(GTK_CONTAINER(win), 10); gtk_window_set_modal(GTK_WINDOW(win), TRUE); vbox = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(win), vbox); name_entry = gtk_entry_new(); gtk_box_pack_start(GTK_BOX(vbox), name_entry, TRUE, TRUE, 5); button = gtk_button_new_from_stock(GTK_STOCK_OK); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(on_button_clicked), win); gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 5); gtk_widget_show_all(win);}void on_send(GtkButton *button, gpointer data){ const gchar *message; if (isconnected == FALSE) return; message = gtk_entry_get_text(GTK_ENTRY(message_entry)); if (g_strcmp0(message, "") == 0) return; sprintf(buf, "%s", message); write(sd, buf, 1024); gtk_entry_set_text(GTK_ENTRY(message_entry), "");}void on_login(GtkWidget *button, gpointer data){ create_win();}void on_delete_event(GtkWidget *widget, GdkEvent *event, gpointer data){ close(sd); gtk_main_quit();}int main(int argc, char *argv[]){ GtkWidget *window; GtkWidget *vbox, *hbox, *button, *label, *view; if (!g_thread_supported()) { g_thread_init(NULL); } else { g_print("thread not supported\n"); } gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(on_delete_event), NULL); gtk_window_set_title(GTK_WINDOW(window), "客户端"); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_container_set_border_width(GTK_CONTAINER(window), 10); vbox = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(window), vbox); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5); label = gtk_label_new("点击登录按钮连接服务器"); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5); login_button = gtk_button_new_with_label("登录"); gtk_box_pack_start(GTK_BOX(hbox), login_button, FALSE, FALSE, 5); g_signal_connect(G_OBJECT(login_button), "clicked", G_CALLBACK(on_login), NULL); view = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(view), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); text = gtk_text_view_new(); gtk_box_pack_start(GTK_BOX(vbox), view, TRUE, TRUE, 5); gtk_container_add(GTK_CONTAINER(view), text); buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5); label = gtk_label_new("输入信息:"); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5); message_entry = gtk_entry_new(); gtk_box_pack_start(GTK_BOX(hbox), message_entry, FALSE, FALSE, 5); button = gtk_button_new_with_label("发送"); gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 5); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(on_send), NULL); gtk_widget_show_all(window); gdk_threads_enter(); gtk_main(); gdk_threads_leave(); return TRUE;}编译运行:
gcc -o client client.c `pkg-config --cflags --libs gtk+-2.0 gthread-2.0`客户端界面:
服务器端显示:
当用户访问量过多时(客户端退出时,服务器并未删除用户信息,须改进):
三、总结
(1)使用fork产生一个子进程与一个用户通讯,当用户较多时便会消耗大量的系统资源并且不能共享多用户间的数据,因此并不适合真正的系统服务仅测试使用。可以采用多线程的服务器。(2)Linux套接字编程的服务器可以采用非阻塞的方式,借鉴select、poll和epoll。
(3)若有建议,请留言,在此先感谢!
1 0
- GTK+浅谈之十三网络编程
- GTK+浅谈之十二数据库编程
- GTK+浅谈之总结
- 【网络编程】之十三、ping程序实现
- 【网络编程】之十三、ping程序实现
- iOS之网络编程---网络协议浅谈
- 浅谈Java网络编程之Socket (1)
- 黑马程序员--网络编程之浅谈
- JavaSE复习之十三 高级特性:网络编程
- 网络编程系列之十三 wireshark安装文件冲突
- Qt浅谈之十三:抓图截屏
- Qt浅谈之十三:抓图截屏
- JAVA(十三)网络通信编程
- GTK+浅谈之三简单计算器
- GTK+浅谈之四定时器的应用
- GTK+浅谈之五等待旋转动画
- GTK+浅谈之八表格列表
- GTK+浅谈之十四Glade使用
- tornado异步(未完成)
- unable to extend temp segment by 128 in tablespace name
- iOS 9多任务分屏要点
- Word文档转换成PDF的两种转换方式
- pymatlib常用函数之figure,plot,subplot,show
- GTK+浅谈之十三网络编程
- zeptojs中获取select选中的option的值
- php对象、数组间的转换
- htmlparser使用指南
- MyBatis入门03 解决字段名与实体类属性名不相同的冲突
- Android菜鸟的成长笔记——Spinner 省市县三级地址选择
- java.lang.ClassCastException: com.sun.org.apache.xerces.internal.dom.DeferredCommentImpl cannot be c
- cocos2dx 常见的49中动作详解
- 网络请求