首页 > 代码库 > 基于socket编程的多人聊天室

基于socket编程的多人聊天室

  先是做完的效果图:

        

    server.c

  1 /* 服务器端 server.c */   2 #include <glib.h>  3 #include <stdio.h>  4 #include <fcntl.h>  5 #include <signal.h>  6 #include <sys/socket.h>  7 #include <sys/types.h>  8 #include <sys/time.h>  9 #include <unistd.h>  10 #include <netdb.h>  11 #include <netinet/in.h> 12 #include <arpa/inet.h>   13 #define MAX_USERS 800   //最大访问人数 14  15 //定义用户数据结构 16 struct _client { 17    gint sd;  18    gboolean in_use;  19    gchar name[64];  20    gchar buf[1024];  21             }; 22 typedef struct _client client; 23  24 //定义用户数据区 25 client user[MAX_USERS]; 26 //定义服务线程 27 void do_service (gpointer id){  28      gint j;  29      char tobuf[1024];  30     while(read(user[GPOINTER_TO_INT(id)].sd,user[GPOINTER_TO_INT(id)].buf,1024)!=-1) 31     { 32         sprintf(tobuf,"%s:%s\n",user[GPOINTER_TO_INT(id)].name, 33         user[GPOINTER_TO_INT(id)].buf); 34          for(j=0; j<MAX_USERS; j++)
        {
35   if(user[j].in_use) 36    { 37 write(user[j].sd,tobuf,1024); 38 //g_print("%s",tobuf); 39   } 40 } 41     } 42 // 43     user[GPOINTER_TO_INT(id)].in_use = FALSE; 44    close(user[GPOINTER_TO_INT(id)].sd); 45     exit(0); 46 47 } 48 int main(int argc, char* argv[]) 49 { 50   gint sd, newsd; 51    struct sockaddr_in *sin; 52    gint slen; 53    gint count = 0; 54    gint flags; 55    gchar buf[1024]; 56    gchar tobuf[1024]; 57    gint length,i,j; 58    if(!g_thread_supported()) 59      g_thread_init(NULL); 60 else 61      g_print("thread not supported\n"); 62 63 sd = socket(AF_INET,SOCK_STREAM,0); //1.......创建套接子 64   if(sd == -1) 65   { 66    g_print("create socket error!\n"); 67 return -1; 68   } 69    sin = g_new(struct sockaddr_in,1); 70     sin->sin_family = AF_INET; 71 sin->sin_port = htons(1234); 72 slen = sizeof(struct sockaddr_in); 73 sin->sin_addr.s_addr=inet_addr("127.0.0.1"); 74 75   if(bind(sd,(struct sockaddr*)sin,slen)<0) //2......绑定 76   { 77    g_print("bind error!\n"); 78    return -1; 79   } 80   if(listen(sd,8)<0) //3......开启监听 81   { 82 g_print("listen error!\n"); return -1; 83   } 84   for(i=0; i<MAX_USERS; i++) //判断访问人数 85    user[i].in_use = FALSE; 86    flags = fcntl(sd,F_GETFL); 87    fcntl(sd,F_SETFL,flags&~O_NDELAY); 88   for(;;) 89   { 90    newsd = accept(sd,sin,&slen); //4....接收 91    if(newsd == -1){ 92    g_print("accept error!\n"); 93    break; 94               } 95     else 96     { 97       if(count >= MAX_USERS) 98       { 99        sprintf(buf,"用户数量过多服务器不能连接。\n");100        write(newsd,buf,1024);101        close(newsd);102       }103       else 104       {105        flags = fcntl(user[i].sd,F_GETFL); 106        fcntl(user[i].sd,F_SETFL,O_NONBLOCK); 107       user[count].sd = newsd; 108        user[count].in_use = TRUE; 109        read(newsd,user[count].name,64); 110         // 创建为用户服务的线程 111       g_thread_create((GThreadFunc)do_service, 112 113       (gpointer)count,TRUE,NULL); 114        count++; 115     }116 }117  }//118   for(;;) 119    close(sd);120    g_free(sin);121 }

client.c

  1 /* 客户端 client.c */  2 #include <gtk/gtk.h>  3 #include<stdio.h>  4 #include<string.h>  5 #include<stdlib.h>  6 #include <sys/types.h>  7 #include <sys/socket.h>  8 #include <netinet/in.h>   9 #include</usr/include/mysql/mysql.h> 10 #define OURPORT 8088 //定义端口号 11 #define MAXLINE 800 12  13 static GtkWidget *text1; 14 static GtkWidget *text2; 15 static GtkWidget *login; 16 static GtkWidget *entry_id; 17 static GtkWidget *entry_pwd; 18 static GtkWidget *regwindow; 19  20 static GtkWidget *reg_entry1; 21 static GtkWidget *reg_entry2; 22  23 static GtkWidget *window1;//聊天室主窗口 24 static GtkWidget *win;//昵称登录窗口 25 static GtkWidget *text_view; 26  27 static GtkTextBuffer *buffer; //显示对话内容的文本显示缓冲区 28 static GtkTextBuffer *buffer1; 29 static GtkTextBuffer *buffer2; 30 static GtkWidget *textview1; //显示输入消息的单行录入控件 31 static GtkWidget *name_entry;//输入用户名的单行录入控件 32 static GtkWidget *login_button; //登录按钮 33 void btn_cal_clicked(); 34 void on_send (GtkButton* button, gpointer data) ; 35 void update_widget_bg(GtkWidget * widget, gchar * img_file); 36  37 gint sd; //套接字句柄 38 struct sockaddr_in s_in; //套接字数据结构 39 gchar username[64]; //用户名 40 gchar buf[1024]; //写缓冲区 41 gchar get_buf[1048]; //读缓冲区 42 gboolean isconnected = FALSE; // 定义逻辑值表示是否连接 43  44 MYSQL_RES *rs; 45 MYSQL_ROW row; 46 MYSQL_RES *exe_sql(char sql[MAXLINE]) 47 { 48     const char *host = "localhost"; 49     const char *user = "root"; 50     const char *pass = ""; 51     const char *db = "talk"; 52      53     /* 定义mysql变量 */ 54     MYSQL_RES *result; 55     MYSQL * mysql; 56     if(!(mysql=mysql_init(NULL))) 57     { 58         printf("mysql_init wrong!"); 59         mysql_close(mysql); 60         exit(0); 61     } 62     /* 连接数据库 */ 63     if (!mysql_real_connect(mysql, host, user, pass, db, 3306, NULL, 0))  64     { 65         printf("connect wrong!"); 66         mysql_close(mysql); 67         exit(0); 68     } 69     printf("%s\n",sql); 70     if(mysql_query(mysql,sql)) 71     { 72         printf("mysql_query_wrong!"); 73         mysql_close(mysql); 74         exit(0); 75     } 76     result = mysql_store_result(mysql);    /* 获取查询结果 */ 77     return result; 78 } 79 //socket通信 80 void get_message(void)  81 {   82     GtkTextIter iter;  83         gchar get_buf[1024];  84         gchar buf[1024];  85     while(read(sd,buf,1024) != -1) // 只要读取数据成功就循环执行 86      {  87         sprintf(get_buf,"%s",buf); 88         printf("%s\n",buf); 89         gdk_threads_enter(); //进入 90         gtk_text_buffer_get_end_iter(buffer,&iter); 91         gtk_text_buffer_insert(buffer,&iter,get_buf,-1);//显示读取的数据 92         gdk_threads_leave(); //离开 93     } 94 } 95 // 连接多人聊天服务器 96 gboolean do_connect(void)  97 {   98     GtkTextIter iter;  99     gint slen; 100     sd = socket(AF_INET,SOCK_STREAM,0);//创建101     printf("%d\n",sd);102     if(sd < 0)103     { 104         gtk_text_buffer_get_end_iter(buffer,&iter);105         gtk_text_buffer_insert(buffer,&iter,"打开套接字时出错!\n",-1);106     return FALSE; 107     }       108     s_in.sin_family = AF_INET;109     s_in.sin_port = htons(1234);110     slen = sizeof(s_in);111     if(connect(sd,&s_in,slen) < 0) //112     { 113         gtk_text_buffer_get_end_iter(buffer,&iter);114         gtk_text_buffer_insert(buffer,&iter,"连接服务器时出错!\n",-1);115         return FALSE; 116     }117     else 118     { 119 120         gtk_text_buffer_get_end_iter(buffer,&iter);121         gtk_text_buffer_insert(buffer,&iter,username,-1);122         gtk_text_buffer_get_end_iter(buffer,&iter);123         gtk_text_buffer_insert(buffer,&iter,"\n成功与服务器连接....\n",-1);124         //125         write(sd,username,64);//向服务器发送用户名//126         isconnected = TRUE;127         return TRUE; 128      }129 } 130 void on_send (GtkButton* button, gpointer data) 131 { 132     //向服务器发送数据133     const char* message; 134     GtkTextIter start;135     GtkTextIter end;136     char sql[MAXLINE];137      if(isconnected==FALSE)138         return; 139     buffer1=gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview1));140     gtk_text_buffer_get_start_iter(buffer1,&start);141     gtk_text_buffer_get_end_iter(buffer1,&end);142     message=gtk_text_buffer_get_text(buffer1,&start,&end,TRUE);143     sprintf(buf,"%s\n",message);144     write(sd,buf,1024);//发送 145     sprintf(sql,"insert into history (user,message,date) values (‘%s‘,‘%s‘,now())",username,message);146     147     rs = exe_sql(sql);148     gtk_text_buffer_set_text(buffer1,"",-1);////清除文字149 150 }     151 void on_login(GtkWidget *button, gpointer data)152 { 153     //点击登录按钮时执行 154     create_win();155 } 156 void cls()//清屏157 {158     gtk_text_buffer_set_text(buffer,"",-1);159 }160 void history()161 {162     int rows_num;163     int count;164     GtkBuilder *gb;165     //查看历史窗口166     GtkWidget *history_win;//查看聊天历史界面167     GtkWidget *history_view;168     char *sql[MAXLINE];169     gb=gtk_builder_new();170     gtk_builder_add_from_file(gb,"history.glade",NULL);171     history_win=GTK_WIDGET(gtk_builder_get_object(gb,"history_win"));172     history_view=GTK_WIDGET(gtk_builder_get_object(gb,"history_view"));173     update_widget_bg(history_win, "ico/bg.jpg");174     gtk_widget_show(GTK_WIDGET(history_win));175     //显示数据176     strcpy(sql,"select * from history where date <=now() and date >=now()-interval 5 minute");177     rs=exe_sql(sql);178     printf("%s\n",sql);179     rows_num=mysql_num_rows(rs);180 181     for(count=0;count<rows_num;count++)182     {183         GtkTextIter end;184         row=mysql_fetch_row(rs);185         buffer1 = gtk_text_view_get_buffer(GTK_TEXT_VIEW(history_view));186         gtk_text_buffer_get_end_iter(buffer1,&end);187         gtk_text_buffer_insert(buffer1, &end, row[1], -1);  188         gtk_text_buffer_insert(buffer1, &end, " : ", -1);189         gtk_text_buffer_insert(buffer1, &end, row[2], -1); 190         gtk_text_buffer_insert(buffer1, &end, "  ", -1);191         gtk_text_buffer_insert(buffer1, &end, row[3], -1); 192         gtk_text_buffer_insert(buffer1, &end, "\n", -1);193     194     }195 }196 //当点击登录窗口的登录按钮时执行197 void on_button_clicked(GtkButton *button, gpointer data)198 {199       buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));  200     gtk_text_buffer_set_text(buffer, "Hello    ", -1); 201     gchar *name;    202     name = gtk_entry_get_text(GTK_ENTRY(name_entry));203     204     sprintf(username,"%s",name);205 206     if(do_connect())207     { 208         gtk_widget_set_sensitive(login_button,FALSE);209         g_thread_create((GThreadFunc)get_message,NULL,FALSE,NULL);210     }211         gtk_widget_destroy(data);212     } 213 214 //当前关闭登录窗口时执行 215 void on_destroy(GtkWidget *widget, GdkEvent *event, gpointer data)216 {217     sprintf(username,"guest");218     if(do_connect()==TRUE)219     { 220         gtk_widget_set_sensitive(login_button,FALSE);221         g_thread_create((GThreadFunc)get_message,NULL,FALSE,NULL);222     }223     gtk_widget_destroy(widget);224 } 225 //背景图片的显示功能226 void update_widget_bg(GtkWidget * widget, gchar * img_file)227 {228     GtkStyle *style;229     GdkPixbuf *pixbuf;230     GdkPixmap *pixmap;231     gint width, height;232 233     pixbuf = gdk_pixbuf_new_from_file(img_file, NULL);234     width = gdk_pixbuf_get_width(pixbuf);235     height = gdk_pixbuf_get_height(pixbuf);236     pixmap = gdk_pixmap_new(NULL, width, height, 24);237     gdk_pixbuf_render_pixmap_and_mask(pixbuf, &pixmap, NULL, 0);238     style = gtk_style_copy(GTK_WIDGET(widget)->style);239     if (style->bg_pixmap[GTK_STATE_NORMAL])240         g_object_unref(style->bg_pixmap[GTK_STATE_NORMAL]);241     style->bg_pixmap[GTK_STATE_NORMAL] = g_object_ref(pixmap);242     style->bg_pixmap[GTK_STATE_ACTIVE] = g_object_ref(pixmap);243     style->bg_pixmap[GTK_STATE_PRELIGHT] = g_object_ref(pixmap);244     style->bg_pixmap[GTK_STATE_SELECTED] = g_object_ref(pixmap);245     style->bg_pixmap[GTK_STATE_INSENSITIVE] = g_object_ref(pixmap);246     gtk_widget_set_style(GTK_WIDGET(widget), style);247     g_object_unref(style);248 }249 void btn_cal(GtkWidget *dialog,gpointer data)250 {251     gtk_widget_destroy(win);252     return FALSE;253 }254 void create_win(void)255 {     //昵称窗口256     GtkBuilder *gb;257     GtkWidget *btn_ok;258     gb=gtk_builder_new();259     gtk_builder_add_from_file(gb,"log.glade",NULL);260         win=GTK_WIDGET(gtk_builder_get_object(gb,"win"));261     name_entry=GTK_WIDGET(gtk_builder_get_object(gb,"name_entry"));262     btn_ok=GTK_WIDGET(gtk_builder_get_object(gb,"btn_ok"));    263     update_widget_bg(win, "ico/bg.jpg");264     gtk_widget_show(GTK_WIDGET(win));265     g_signal_connect(GTK_OBJECT(btn_ok),"clicked",G_CALLBACK(on_button_clicked),win);266 } 267 //聊天室关闭按钮268 void button1_clicked()269 {270     close(sd);//关闭 271     gtk_main_quit();272 }273 /* 弹出对话框代码开始*/274 void show_info(char *msgtip)275 {276     GtkWidget *dialog;277     dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, msgtip);278     gtk_window_set_title(GTK_WINDOW(dialog), "Information");279     gtk_dialog_run(GTK_DIALOG(dialog));280     gtk_widget_destroy(dialog);281 }282 /*glade主界面*/283 #define w_(builder,type,name) name=GTK_##type(gtk_builder_get_object(builder,#name))284 GtkBuilder* gtk_load_glade(gchar* filename)285 286 {287 288   GtkBuilder *gb;289 290   gb=gtk_builder_new();291 292   if(!gtk_builder_add_from_file(gb,filename,NULL)) 293       return NULL;294 295   gtk_builder_connect_signals(gb,NULL);296 297   return gb;298 299 }300 void cal_widget_init()301 302 {303 304   gtk_widget_show(GTK_WIDGET(window1));305 306 }307 308 void cal_get_widgets(GtkBuilder* gb)309 310 {311 312   w_(gb,WINDOW,login);313 314   w_(gb,ENTRY,entry_id);315   w_(gb,ENTRY,entry_pwd);316  317   w_(gb,WINDOW,window1);318 319   w_(gb,TEXT_VIEW,text_view);320   w_(gb,WIDGET,textview1);321   w_(gb,ENTRY,name_entry);322 323 }324 //登录按钮的响应函数325 void mysql_connect()326 {327     char sql[MAXLINE];328     const gchar *entry1;329     const gchar *entry2;330     entry1=gtk_entry_get_text(GTK_ENTRY(entry_id));331     entry2=gtk_entry_get_text(GTK_ENTRY(entry_pwd));332 333     if (strcmp(entry1, "") == 0) {334         show_info("帐号不能为空!");335         return;336     }337     if (strcmp(entry2, "") == 0) {338         show_info("密码不能为空!");339         return;340     }341 342     sprintf(sql,"select count(*) from users where user=‘%s‘ and passwd=‘%s‘",entry1,entry2);343     344     rs=exe_sql(sql);345     346         row=mysql_fetch_row(rs);347     348     const gchar *a=row[0];349     350     if(strcmp(a,"1")==0)351         {352             show_info("成功登录!");353              if(!g_thread_supported())354             g_thread_init(NULL); 355             //初始线程 356 357               GtkBuilder *gb;358 359               gb=gtk_load_glade("try1.glade");360             gtk_widget_destroy(login);361             if(gb==NULL)  362             return -1;363 364               cal_get_widgets(gb);365 366               cal_widget_init();367             return 0; 368         }369     else370         371         show_info("用户名或密码失败\n");372         return;373 }374 //创建button按钮375 GtkWidget *create_button()376 {377     GtkWidget *button = gtk_button_new();378     return button;379 }380 //退出按钮381 void btn_cal_clicked(GtkWidget *dialog,gpointer data)382 {383     gtk_widget_destroy(regwindow);384     return FALSE;385 }386 //注册的响应函数387 void reg_btn2_clicked()388 {389     int rows;390     MYSQL_ROW *mysql_row; 391     const char *name=gtk_entry_get_text(GTK_ENTRY(reg_entry1));392     const char *passwd=gtk_entry_get_text(GTK_ENTRY(reg_entry2));393     if (strcmp(name, "") == 0) 394     {395         show_info("帐号不能为空!");396         return;397     }398     if (strcmp(passwd, "") == 0)399     {400         show_info("密码不能为空!");401         return;402     }403     char sql[MAXLINE];404     char query[MAXLINE];405     sprintf(query,"select * from users where user=‘%s‘",name);406     rs = exe_sql(query);407     rows=mysql_num_rows(rs);408     //mysql_row=mysql_fetch_row(rs);409     //const gchar *b=row[0];410     411     if(rows>=1)412     {    413         show_info("用户名已被注册\n");414         return;415     }416     else417     sprintf(sql, "insert into users(user,passwd) values(‘%s‘,‘%s‘)",name,passwd);418     rs = exe_sql(sql);419     show_info("注册成功");420 }421 //注册响应函数+注册界面422 void btn_reg_clicked()423 {424     GtkBuilder *gb;425     GtkWidget *reg_btn1;426     GtkWidget *reg_btn2;427     gb=gtk_builder_new();428     gtk_builder_add_from_file(gb,"reg.glade",NULL);429         regwindow=GTK_WIDGET(gtk_builder_get_object(gb,"regwindow"));430     reg_entry1=GTK_WIDGET(gtk_builder_get_object(gb,"reg_entry1"));431     reg_entry2=GTK_WIDGET(gtk_builder_get_object(gb,"reg_entry2"));432     reg_btn1=GTK_WIDGET(gtk_builder_get_object(gb,"reg_btn1"));433     reg_btn2=GTK_WIDGET(gtk_builder_get_object(gb,"reg_btn2"));434     update_widget_bg(regwindow, "ico/bg.jpg");    435     gtk_widget_show(GTK_WIDGET(regwindow));436     g_signal_connect(GTK_OBJECT(reg_btn1),"clicked",G_CALLBACK(btn_cal_clicked),regwindow);437     g_signal_connect(GTK_OBJECT(reg_btn2),"clicked",G_CALLBACK(reg_btn2_clicked),regwindow);438 }439 GtkWidget *create_window() //创建窗体和控件!!440 {441     gtk_init(NULL, NULL); //初始化442       GtkBuilder *gb;443 444       gb=gtk_load_glade("client.glade");445 446       cal_get_widgets(gb);447       update_widget_bg(login, "ico/bg.jpg");448 449       gtk_widget_show_all(login); //显示窗体和控件450       return 0; 451 }452 int main(int argc,char *argv[])453 {454     455     create_window(); //创建窗体和控件!!456     gtk_main(); //事件循环处理457     return 0;458 }

由于编写时调用了glade界面和mysql数据库,界面和表就不再上传了。

基于socket编程的多人聊天室