网络编程是Linux功能的强项,Gtk+2.0结合Linux系统的网络编程编写服务器和客户端。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define OURPORT 8088
void 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连接。
#include
#include
#include
#include
#include
#define OURPORT 8088
gint 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`
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define OURPORT 8088
#define MAX_USERS 8
struct _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`
运行,等待客户端的连接。
#include
#include
#include
#include
#include
#define OURPORT 8088
gint 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`
客户端界面: