嵌入式成长轨迹25 【Linux应用编程强化】【Linux下的C编程 下】【实例:客户端/服务器端程序】
给出一个客户/服务器程序开发的案例,实现从服务器状态的远程监视功能。同时,客户端采用图形界面来显示数据。这个案例涵盖了网络编程和GUI编程的相关知识,读者应该注意其中的结合点。具体内容包括:
服务器端程序设计
客户端程序设计
一 服务器端程序设计
服务器端程序的功能是接受客户端的连接,然后提供其状态信息,例如CPU的使用率、内存的分配情况等,这些信息我们通过访问/proc文件系统来获得。
1 /* server.c */ 2 3 #include <stdlib.h> 4 5 #include <stdio.h> 6 7 #include <unistd.h> 8 9 #include <errno.h> 10 11 #include <string.h> 12 13 #include <sys/types.h> 14 15 #include <netinet/in.h> 16 17 #include <sys/socket.h> 18 19 #include <arpa/inet.h> 20 21 #define SERV_PORT 2395 /* 服务器监听端口号 */ 22 23 #define BACKLOG 10 /* 请求队列的长度数 */ 24 25 #define BUF_SIZE 1024 /* 缓冲区的长度 */ 26 27 #define MEM_SIZE 32 28 29 30 31 struct cpustatus 32 33 { 34 35 long total; /* 系统从启动到现在的总时间 */ 36 37 float user; /* 系统从启动到现在用户态的CPU时间(百分比) */ 38 39 float nice; /* 系统从启动到现在nice值为负的进程所占用的CPU时间(百分比) */ 40 41 float system; /* 系统从启动到现在核心态的CPU时间(百分比) */ 42 43 float idle; /* 系统从启动到现在除I/O等待以外的其他等待时间(百分比) */ 44 45 }; 46 47 struct meminfo 48 49 { 50 51 char total[MEM_SIZE]; /* 系统的总内存空间 */ 52 53 char free[MEM_SIZE]; /* 系统的空闲内存空间 */ 54 55 }; 56 57 void get_cpu_status(struct cpustatus *); /* 获取处理器信息 */ 58 59 void get_mem_info(struct meminfo *); /* 获取内存信息 */ 60 61 62 63 int main() 64 65 { 66 67 int ret; 68 69 int pid; /* 定义进程标识符 */ 70 71 int sockfd; /* 定义监听Socket描述符 */ 72 73 int clientsfd; /* 定义数据传输Socket描述符 */ 74 75 struct sockaddr_in host_addr; /* 本机IP地址和端口号信息 */ 76 77 struct sockaddr_in client_addr; /* 客户端IP地址和端口号信息 */ 78 79 unsigned int addrlen; 80 81 char buf[BUF_SIZE]; /* 定义缓冲区 */ 82 83 struct cpustatus cpu_stat; 84 85 struct meminfo mem_info; 86 87 int cnt; 88 89 int size; 90 91 /* 创建套接字 */ 92 93 sockfd = socket(AF_INET, SOCK_STREAM, 0); 94 95 if(sockfd == -1) /* 如果套接字创建失败,输出错误信息并退出 */ 96 97 { 98 99 printf("socket error\n"); 100 101 exit(1); 102 103 } 104 105 /* 将套接字与IP地址和端口号进行绑定 */ 106 107 host_addr.sin_family = AF_INET; /* TCP/IP协议 */ 108 109 host_addr.sin_port = htons(SERV_PORT); /* 让系统随机选择一个未被占用的端口号 */ 110 111 host_addr.sin_addr.s_addr = INADDR_ANY; /* 本机IP地址 */ 112 113 bzero(&(host_addr.sin_zero), 8); /* 清零 */ 114 115 ret = bind(sockfd, (struct sockaddr *)&host_addr, sizeof(struct sockaddr)); /* 绑定 */ 116 117 if(ret == -1) /* 如果套接字绑定失败,输出错误信息并退出 */ 118 119 { 120 121 printf("bind error\n"); 122 123 exit(1); 124 125 } 126 127 /* 将套接字设为监听模式,以等待连接请求 */ 128 129 ret = listen(sockfd, BACKLOG); 130 131 if(ret == -1) { 132 133 perror("listen error\n"); 134 135 exit(1); 136 137 } 138 139 printf("Waiting for the client connection.\n "); 140 141 /* 循环处理客户端的请求 */ 142 143 while(1) 144 145 { 146 147 addrlen = sizeof(struct sockaddr_in); 148 149 clientsfd = accept(sockfd, (struct sockaddr *)&client_addr, &addrlen); /* 接受一个客户端连接 */ 150 151 if(clientsfd == -1) 152 153 { 154 155 perror("accept error\n"); 156 157 continue; 158 159 } 160 161 pid = fork(); /* 创建子进程 */ 162 163 if(pid<0) /* 如果进程创建失败,输出错误信息并退出 */ 164 165 { 166 167 perror("fork error\n"); 168 169 exit(1); 170 171 } 172 173 if(pid==0) /* 子进程,处理客户端的请求*/ 174 175 { 176 177 close(sockfd); /* 关闭父进程的套接字 */ 178 179 printf("Client IP : %s\n", inet_ntoa(client_addr.sin_addr)); /* 输出客户端IP地址 */ 180 181 /* 获取处理器信息 */ 182 183 get_cpu_status(&cpu_stat); 184 185 size = sizeof(struct cpustatus); 186 187 memcpy(buf, &cpu_stat, size); 188 189 /* 获取内存信息 */ 190 191 get_mem_info(&mem_info); 192 193 memcpy(buf+size, &mem_info, sizeof(struct meminfo)); 194 195 /* 发送数据 */ 196 197 cnt = send(clientsfd, buf, BUF_SIZE, 0); 198 199 if(cnt == -1) 200 201 { 202 203 perror("send error\n"); 204 205 exit(1); 206 207 } 208 209 printf("Done!\n", buf); /* 程序测试使用 */ 210 211 close(clientsfd); /* 关闭当前客户端连接 */ 212 213 exit(0); /* 子进程退出 */ 214 215 } 216 217 close(clientsfd); /* 父进程,关闭子进程的套接字,准备接受下一个客户端连接 */ 218 219 } 220 221 return 0; 222 223 } 224 225 226 227 void get_cpu_status(struct cpustatus *cpu_stat) 228 229 { 230 231 long total; 232 233 float user, nice, system, idle; 234 235 long cpu[21]; 236 237 char text[201]; 238 239 FILE *fp; 240 241 fp = fopen("/proc/stat", "r"); /* 如果/proc/stat文件 */ 242 243 if (fp == NULL) /* 如果文件打开失败,输出错误信息并退出 */ 244 245 { 246 247 printf("open stat failed\n"); 248 249 exit(1); 250 251 } 252 253 while(fgets(text, 200, fp) != NULL) /* 提取处理器信息 */ 254 255 { 256 257 if(strstr(text, "cpu")) 258 259 { 260 261 sscanf(text, "%s %f %f %f %f", cpu, &user, &nice, &system, &idle); 262 263 } 264 265 } 266 267 fclose(fp); /* 关闭文件 */ 268 269 /* 进行各类CPU时间 */ 270 271 total = user + nice + system + idle; 272 273 user = (user / total) * 100; 274 275 nice = (nice / total) * 100; 276 277 system = (system / total) * 100; 278 279 idle = (idle / total) * 100; 280 281 /* 对结构体各成员进行赋值 */ 282 283 cpu_stat->total = total; 284 285 cpu_stat->user = user; 286 287 cpu_stat->nice = nice; 288 289 cpu_stat->system = system; 290 291 cpu_stat->idle = idle; 292 293 return; 294 295 } 296 297 298 299 void get_mem_info(struct meminfo *minfo) 300 301 { 302 303 int i, j; 304 305 char total[MEM_SIZE]; 306 307 char free[MEM_SIZE]; 308 309 char temp[MEM_SIZE*2]; 310 311 FILE *fp; 312 313 fp = fopen("/proc/meminfo", "r"); /* 如果/proc/meminfo文件 */ 314 315 if (fp == NULL) /* 如果文件打开失败,输出错误信息并退出 */ 316 317 { 318 319 printf("open meminfo failed\n"); 320 321 exit(1); 322 323 } 324 325 fgets(temp, MEM_SIZE*2, fp); 326 327 strcpy(total, temp); /* 系统的总内存空间信息(字符串) */ 328 329 fgets(temp, MEM_SIZE*2, fp); 330 331 strcpy(free, temp); /* 系统的空闲内存空间信息(字符串) */ 332 333 fclose(fp); /* 关闭文件 */ 334 335 if(strlen(total) > 0) /* 提取总内存空间信息字符串中的数值部分 */ 336 337 { 338 339 for(i=0,j=0; i<strlen(total); i++) 340 341 { 342 343 if(isdigit(total[i])) 344 345 minfo->total[j++] = total[i]; 346 347 } 348 349 minfo->total[j] = '\0'; /* 字符串结束符 */ 350 351 } 352 353 if(strlen(free) > 0) /* 提取空闲内存空间信息字符串中的数值部分 */ 354 355 { 356 357 for(i=0,j=0; i<strlen(free); i++) 358 359 { 360 361 if(isdigit(free[i])) 362 363 minfo->free[j++] = free[i]; 364 365 } 366 367 minfo->free[j] = '\0'; /* 字符串结束符 */ 368 369 } 370 371 return; 372 373 }
二 客户端程序设计
客户端程序我们分两步来实现,首先在字符界面下设计实现,调试通过后,再设计开发图形界面。
1 字符界面客户端程序
首先开发字符界面下的客户端程序,该程序的功能比较简单,连接服务器,获取其状态信息,并输出到屏幕。
1 /* client.c */ 2 3 #include <stdlib.h> 4 5 #include <stdio.h> 6 7 #include <unistd.h> 8 9 #include <errno.h> 10 11 #include <string.h> 12 13 #include <sys/types.h> 14 15 #include <netinet/in.h> 16 17 #include <sys/socket.h> 18 19 #define SERV_PORT 2395 /* 服务器监听端口号 */ 20 21 #define BUF_SIZE 1024 /* 缓冲区的长度 */ 22 23 #define MEM_SIZE 32 24 25 26 27 struct cpustatus /* 处理器信息 */ 28 29 { 30 31 long total; 32 33 float user; 34 35 float nice; 36 37 float system; 38 39 float idle; 40 41 }; 42 43 struct meminfo /* 内存信息 */ 44 45 { 46 47 char total[MEM_SIZE]; 48 49 char free[MEM_SIZE]; 50 51 }; 52 53 54 55 int main(int argc, char **argv) 56 57 { 58 59 int ret; 60 61 int sockfd; /* 定义Socket描述符 */ 62 63 struct sockaddr_in serv_addr; /* 服务器IP地址和端口号信息 */ 64 65 char buf[BUF_SIZE]; /* 定义缓冲区 */ 66 67 struct cpustatus cpu_stat; 68 69 struct meminfo mem_info; 70 71 int cnt; 72 73 int size; 74 75 if(argc != 2) /* 检查命令行参数个数是否正确 */ 76 77 { 78 79 printf("arguments error.\n"); 80 81 exit(1); 82 83 } 84 85 /* 创建套接字 */ 86 87 sockfd = socket(AF_INET, SOCK_STREAM, 0); 88 89 if(sockfd == -1) /* 如果套接字创建失败,输出错误信息并退出 */ 90 91 { 92 93 printf("socket error\n"); 94 95 exit(1); 96 97 } 98 99 /* 向服务器发出连接请求 */ 100 101 serv_addr.sin_family = AF_INET; /* TCP/IP协议 */ 102 103 serv_addr.sin_port = htons(SERV_PORT); /* 服务器端口号,并转换为网络字节顺序 */ 104 105 serv_addr.sin_addr.s_addr = inet_addr(argv[1]); /* 服务器的IP地址 */ 106 107 bzero(&(serv_addr.sin_zero), 8); /* 清零 */ 108 109 ret = connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)); /* 连接 */ 110 111 if(ret == -1) /* 如果连接失败,输出错误信息并退出 */ 112 113 { 114 115 printf("connect error\n"); 116 117 exit(1); 118 119 } 120 121 /* 接收数据 */ 122 123 cnt = recv(sockfd, buf, BUF_SIZE, 0); 124 125 if(cnt == -1) 126 127 { 128 129 perror("recv error\n"); 130 131 exit(1); 132 133 } 134 135 size = sizeof(struct cpustatus); 136 137 memcpy(&cpu_stat, buf, size); 138 139 memcpy(&mem_info, buf+size, sizeof(struct meminfo)); 140 141 /* 输出接收到数据 */ 142 143 printf("CPU Information\n"); 144 145 printf("------------------------\n"); 146 147 printf("user :\t\t %.2f\%\n", cpu_stat.user); 148 149 printf("nice :\t\t %.2f\%\n", cpu_stat.nice); 150 151 printf("system :\t %.2f\%\n", cpu_stat.system); 152 153 printf("idle :\t\t %.2f\%\n", cpu_stat.idle); 154 155 printf("Memory Information\n"); 156 157 printf("------------------------\n"); 158 159 printf("total :\t\t %s kB\n",mem_info.total); 160 161 printf("free :\t\t %s kB \n",mem_info.free); 162 163 close(sockfd); /* 关闭套接字 */ 164 165 return 0; 166 167 }
2 图形界面客户端程序
接下来设计开发客户端的图形界面,这里使用Glade来协助完成。
1 /* 2 3 * Initial main.c file generated by Glade. Edit as required. 4 5 * Glade will not overwrite this file. 6 7 */ 8 9 10 11 #ifdef HAVE_CONFIG_H 12 13 # include <config.h> 14 15 #endif 16 17 18 19 #include <gtk/gtk.h> 20 21 22 23 #include "interface.h" 24 25 #include "support.h" 26 27 28 29 GtkWidget *entry1; 30 31 GtkWidget *textview1; 32 33 int 34 35 main (int argc, char *argv[]) 36 37 { 38 39 GtkWidget *window1; 40 41 42 43 #ifdef ENABLE_NLS 44 45 bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR); 46 47 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); 48 49 textdomain (GETTEXT_PACKAGE); 50 51 #endif 52 53 54 55 gtk_set_locale (); 56 57 gtk_init (&argc, &argv); 58 59 60 61 add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps"); 62 63 64 65 /* 66 67 * The following code was added by Glade to create one of each component 68 69 * (except popup menus), just so that you see something after building 70 71 * the project. Delete any components that you don't want shown initially. 72 73 */ 74 75 window1 = create_window1 (); 76 77 gtk_widget_show (window1); 78 79 80 81 gtk_main (); 82 83 return 0; 84 85 } 86 87 88 89 /* 90 91 * DO NOT EDIT THIS FILE - it is generated by Glade. 92 93 */ 94 95 96 97 #ifdef HAVE_CONFIG_H 98 99 # include <config.h> 100 101 #endif 102 103 104 105 #include <sys/types.h> 106 107 #include <sys/stat.h> 108 109 #include <unistd.h> 110 111 #include <string.h> 112 113 #include <stdio.h> 114 115 116 117 #include <gdk/gdkkeysyms.h> 118 119 #include <gtk/gtk.h> 120 121 122 123 #include "callbacks.h" 124 125 #include "interface.h" 126 127 #include "support.h" 128 129 130 131 #define GLADE_HOOKUP_OBJECT(component,widget,name) \ 132 133 g_object_set_data_full (G_OBJECT (component), name, \ 134 135 gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref) 136 137 138 139 #define GLADE_HOOKUP_OBJECT_NO_REF(component,widget,name) \ 140 141 g_object_set_data (G_OBJECT (component), name, widget) 142 143 144 145 GtkWidget* 146 147 create_window1 (void) 148 149 { 150 151 GtkWidget *window1; 152 153 GtkWidget *fixed1; 154 155 GtkWidget *fixed2; 156 157 extern GtkWidget *entry1; 158 159 extern GtkWidget *textview1; 160 161 GtkWidget *label2; 162 163 GtkWidget *label1; 164 165 GtkWidget *button1; 166 167 168 169 window1 = gtk_window_new (GTK_WINDOW_TOPLEVEL); 170 171 gtk_window_set_title (GTK_WINDOW (window1), _("remote monitor")); 172 173 174 175 fixed1 = gtk_fixed_new (); 176 177 gtk_widget_show (fixed1); 178 179 gtk_container_add (GTK_CONTAINER (window1), fixed1); 180 181 gtk_widget_set_size_request (fixed1, 264, 302); 182 183 184 185 fixed2 = gtk_fixed_new (); 186 187 gtk_widget_show (fixed2); 188 189 gtk_fixed_put (GTK_FIXED (fixed1), fixed2, 136, 104); 190 191 gtk_widget_set_size_request (fixed2, 50, 50); 192 193 194 195 entry1 = gtk_entry_new (); 196 197 gtk_widget_show (entry1); 198 199 gtk_fixed_put (GTK_FIXED (fixed1), entry1, 104, 224); 200 201 gtk_widget_set_size_request (entry1, 144, 24); 202 203 gtk_entry_set_invisible_char (GTK_ENTRY (entry1), 8226); 204 205 206 207 textview1 = gtk_text_view_new (); 208 209 gtk_widget_show (textview1); 210 211 gtk_fixed_put (GTK_FIXED (fixed1), textview1, 16, 42); 212 213 gtk_widget_set_size_request (textview1, 232, 172); 214 215 216 217 label2 = gtk_label_new (_("Server Information :")); 218 219 gtk_widget_show (label2); 220 221 gtk_fixed_put (GTK_FIXED (fixed1), label2, 10, 16); 222 223 gtk_widget_set_size_request (label2, 160, 24); 224 225 226 227 label1 = gtk_label_new (_("IP Address:\n")); 228 229 gtk_widget_show (label1); 230 231 gtk_fixed_put (GTK_FIXED (fixed1), label1, 16, 227); 232 233 gtk_widget_set_size_request (label1, 80, 20); 234 235 gtk_label_set_justify (GTK_LABEL (label1), GTK_JUSTIFY_CENTER); 236 237 238 239 button1 = gtk_button_new_with_mnemonic (_("Update")); 240 241 gtk_widget_show (button1); 242 243 gtk_fixed_put (GTK_FIXED (fixed1), button1, 176, 256); 244 245 gtk_widget_set_size_request (button1, 70, 29); 246 247 248 249 g_signal_connect ((gpointer) entry1, "activate", 250 251 G_CALLBACK (on_entry1_activate), 252 253 NULL); 254 255 g_signal_connect ((gpointer) button1, "clicked", 256 257 G_CALLBACK (on_button1_clicked), 258 259 NULL); 260 261 262 263 /* Store pointers to all widgets, for use by lookup_widget(). */ 264 265 GLADE_HOOKUP_OBJECT_NO_REF (window1, window1, "window1"); 266 267 GLADE_HOOKUP_OBJECT (window1, fixed1, "fixed1"); 268 269 GLADE_HOOKUP_OBJECT (window1, fixed2, "fixed2"); 270 271 GLADE_HOOKUP_OBJECT (window1, entry1, "entry1"); 272 273 GLADE_HOOKUP_OBJECT (window1, textview1, "textview1"); 274 275 GLADE_HOOKUP_OBJECT (window1, label2, "label2"); 276 277 GLADE_HOOKUP_OBJECT (window1, label1, "label1"); 278 279 GLADE_HOOKUP_OBJECT (window1, button1, "button1"); 280 281 282 283 return window1; 284 285 } 286 287 288 289 #ifdef HAVE_CONFIG_H 290 291 # include <config.h> 292 293 #endif 294 295 296 297 #include <gtk/gtk.h> 298 299 300 301 #include "callbacks.h" 302 303 #include "interface.h" 304 305 #include "support.h" 306 307 308 309 #include <stdlib.h> 310 311 #include <stdio.h> 312 313 #include <unistd.h> 314 315 #include <errno.h> 316 317 #include <string.h> 318 319 #include <sys/types.h> 320 321 #include <netinet/in.h> 322 323 #include <sys/socket.h> 324 325 #define SERV_PORT 2395 /* 服务器监听端口号 */ 326 327 #define BUF_SIZE 1024 /* 缓冲区的长度 */ 328 329 #define MEM_SIZE 32 330 331 332 333 334 335 336 337 struct cpustatus /* 处理器信息 */ 338 339 { 340 341 long total; 342 343 float user; 344 345 float nice; 346 347 float system; 348 349 float idle; 350 351 }; 352 353 struct meminfo /* 内存信息 */ 354 355 { 356 357 char total[MEM_SIZE]; 358 359 char free[MEM_SIZE]; 360 361 }; 362 363 364 365 366 367 368 369 370 371 void 372 373 on_button1_clicked (GtkButton *button, 374 375 gpointer user_data) 376 377 { 378 379 380 381 int ret; 382 383 int sockfd; /* 定义Socket描述符 */ 384 385 struct sockaddr_in serv_addr; /* 服务器IP地址和端口号信息 */ 386 387 char buf[BUF_SIZE]; /* 定义缓冲区 */ 388 389 struct cpustatus cpu_stat; 390 391 struct meminfo mem_info; 392 393 int i, cnt; 394 395 int size; 396 397 char out[6][MEM_SIZE]; 398 399 sockfd = socket(AF_INET, SOCK_STREAM, 0); 400 401 if(sockfd == -1) /* 如果套接字创建失败,输出错误信息并退出 */ 402 403 { 404 405 printf("socket error\n"); 406 407 exit(1); 408 409 } 410 411 412 413 extern GtkWidget *entry1; 414 415 416 417 const gchar *entry_text; 418 419 entry_text = gtk_entry_get_text(entry1); 420 421 422 423 424 425 /* 向服务器发出连接请求 */ 426 427 serv_addr.sin_family = AF_INET; /* TCP/IP协议 */ 428 429 serv_addr.sin_port = htons(SERV_PORT); /* 服务器端口号,并转换为网络字节顺序 */ 430 431 serv_addr.sin_addr.s_addr = inet_addr(entry_text); /* 服务器的IP地址 */ 432 433 bzero(&(serv_addr.sin_zero), 8); /* 清零 */ 434 435 ret = connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)); /* 连接 */ 436 437 if(ret == -1) /* 如果连接失败,输出错误信息并退出 */ 438 439 { 440 441 printf("connect error\n"); 442 443 exit(1); 444 445 } 446 447 /* 接收数据 */ 448 449 cnt = recv(sockfd, buf, BUF_SIZE, 0); 450 451 if(cnt == -1) 452 453 { 454 455 perror("recv error\n"); 456 457 exit(1); 458 459 } 460 461 size = sizeof(struct cpustatus); 462 463 memcpy(&cpu_stat, buf, size); 464 465 memcpy(&mem_info, buf+size, sizeof(struct meminfo)); 466 467 /* 输出接收到数据 */ 468 469 470 471 printf("Entry contents : %s\n", entry_text); 472 473 extern GtkWidget *textview1; 474 475 // const gchar *entry_text; 476 477 GtkTextBuffer *buffer; 478 479 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW (textview1));//取得文本缓冲区 480 481 482 483 //PangoFontDescription *fontDesc; 484 485 // fontDesc = pango_font_description_from_string("Courier Pitch Bold 12"); 486 487 488 489 // gtk_widget_modify_font(textview1, fontDesc); 490 491 GtkTextIter start, end; 492 493 //gtk_text_buffer_get_start_iter(buffer,&end); 494 495 //gtk_text_buffer_get_end_iter(buffer,&end); 496 497 //end = start; 498 499 500 501 sprintf(out[0],"user :\t\t %.2f\%\n", cpu_stat.user); 502 503 sprintf(out[1],"nice :\t\t %.2f\%\n", cpu_stat.nice); 504 505 sprintf(out[2],"system :\t %.2f\%\n", cpu_stat.system); 506 507 sprintf(out[3],"idle :\t\t %.2f\%\n", cpu_stat.idle); 508 509 510 511 sprintf(out[4],"total :\t\t %s kB\n",mem_info.total); 512 513 sprintf(out[5],"free :\t\t %s kB \n",mem_info.free); 514 515 gtk_text_buffer_get_start_iter(buffer,&end); 516 517 518 519 for(i=5; i>=0; i--) 520 521 { 522 523 524 525 gtk_text_buffer_get_start_iter(buffer,&end); 526 527 528 529 if(i == 3) 530 531 { 532 533 gtk_text_buffer_insert(buffer,&end, "Memory\n-------------------------\n", -1); 534 535 gtk_text_buffer_get_start_iter(buffer,&end); 536 537 } 538 539 gtk_text_buffer_insert(buffer,&end, out[i], -1);/* gtk_text_insert (GTK_TEXT_VIEW(textview1), NULL, &textview1->style->black, NULL, "Supports ", -1);*/ 540 541 542 543 } 544 545 gtk_text_buffer_get_start_iter(buffer,&end); 546 547 gtk_text_buffer_insert(buffer,&end, "CPU\n-------------------------\n", -1); 548 549 close(sockfd); /* 关闭套接字 */ 550 551 return 0; 552 553 554 555 556 557 } 558 559 void 560 561 on_entry1_activate (GtkEntry *entry, gpointer user_data) 562 563 { 564 565 const gchar *entry_text; 566 567 entry_text = gtk_entry_get_text(entry); 568 569 printf("Entry contents : %s\n", entry_text); 570 571 }
三小结
这里基于网络编程和GUI编程技术设计实现了一个客户/服务器程序。总的来说,程序还是比较简单、容易理解的。感兴趣的同学还可以在该程序的基础上进行优化,例如将界面加工得更为美观,或添加一些新的功能。