linux 仿QQ 2.0版本
这个版本对上一个版本进行了一些更改,实现了服务端–>客户端,客户端–》客户端,但是并不算是很友好,此版本还是保留在本地上的传输,下一个版本将会在不同ip地址下面的传输(前提是在同一个局域网),我想在下一个版本实现跨平台,同时实现客户端到服务端和客户端的文件传输
具体的表结构看我的第一个版本(Linux 应用程序中)
客户端的代码:
main.c
/*
* 1.2
编译:gcc view.c -o view `pkg-config --cflags --libs gtk+-2.0`
*/
#include<gtk/gtk.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "view.h"
static GtkWidget* entry1;
static GtkWidget* entry2;
GtkWidget* window;
void on_button_clicked (GtkWidget* button,gpointer data)
{
/*void gtk_entry_set_text(Gtk_Entry *entry,const gchr *text)
* 将新的内容取代文本输入构件当前的内容。
*const gchar *gtk_entry_get_text(GtkEntry *entry)
* 获得当前文本输入构件的内容
*/
if((int)data == 1){
gtk_entry_set_text(GTK_ENTRY(entry1),"");
gtk_entry_set_text(GTK_ENTRY(entry2),"");
}
else if ((int)data == 2){
const gchar* username = gtk_entry_get_text(GTK_ENTRY(entry1));
const gchar* password = gtk_entry_get_text(GTK_ENTRY(entry2));
mydb_init();
if(mydb_test(mysql,username,password)==1)
{
if(write_to_file("login success!")==0)
{
exit(-1);
}
mydb_destory(mysql);
//登陆到客户端窗口程序
execv("./client", NULL);
}
else
{
if(write_to_file("login failed!")==0)
{
exit(-1);
}
exit(-1);
}
}
else if((int)data == 3){
/*改变文本空的可编辑状态*/
gtk_editable_set_editable(GTK_EDITABLE(entry1),GTK_TOGGLE_BUTTON(button)->active);
gtk_editable_set_editable(GTK_EDITABLE(entry2),GTK_TOGGLE_BUTTON(button)->active);
}
}
int main(int argc,char* argv[])
{
GtkWidget* box;
GtkWidget* box1;
GtkWidget* box2;
GtkWidget* box3;
GtkWidget* label1;
GtkWidget* label2;
GtkWidget* button;
GtkWidget* sep;
//初始化
gtk_init(&argc,&argv);
//设置窗口
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(GTK_OBJECT(window),"destroy",GTK_SIGNAL_FUNC(closeApp),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),20);
box = gtk_vbox_new(FALSE,0);
gtk_container_add(GTK_CONTAINER(window),box);
box1 = gtk_hbox_new(FALSE,0);
gtk_box_pack_start(GTK_BOX(box),box1,FALSE,FALSE,5);
box2 = gtk_hbox_new(FALSE,0);
gtk_box_pack_start(GTK_BOX(box),box2,FALSE,FALSE,5);
sep = gtk_hseparator_new();//分割线
gtk_box_pack_start(GTK_BOX(box),sep,FALSE,FALSE,5);
box3 = gtk_hbox_new(FALSE,0);
gtk_box_pack_start(GTK_BOX(box),box3,TRUE,TRUE,5);
label1 = gtk_label_new("用户名:");
entry1 = gtk_entry_new();
gtk_box_pack_start(GTK_BOX(box1),label1,FALSE,FALSE,5);
gtk_box_pack_start(GTK_BOX(box1),entry1,FALSE,FALSE,5);
label2 = gtk_label_new("密 码:");
entry2 = gtk_entry_new();
/*设置输入文本不可见*/
gtk_entry_set_visibility(GTK_ENTRY(entry2),FALSE);
gtk_box_pack_start(GTK_BOX(box2),label2,FALSE,FALSE,5);
gtk_box_pack_start(GTK_BOX(box2),entry2,FALSE,FALSE,5);
button = gtk_check_button_new_with_label("Editable");
g_signal_connect(G_OBJECT(button),"clicked",G_CALLBACK(on_button_clicked),(gpointer)3);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),TRUE);
gtk_box_pack_start(GTK_BOX(box3),button,TRUE,TRUE,10);
gtk_widget_show(button);
button = gtk_button_new_with_label("清空");
g_signal_connect(G_OBJECT(button),"clicked",G_CALLBACK(on_button_clicked),(gpointer)1);
gtk_box_pack_start(GTK_BOX(box3),button,TRUE,TRUE,10);
gtk_widget_show(button);
button = gtk_button_new_with_label("确认");
g_signal_connect(G_OBJECT(button),"clicked",G_CALLBACK(on_button_clicked),(gpointer)2);
g_signal_connect_swapped(G_OBJECT(button),"clicked",G_CALLBACK(gtk_widget_destroy),window);
gtk_box_pack_start(GTK_BOX(box3),button,TRUE,TRUE,5);
gtk_widget_show(button);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
view.h:
/*
* 1.2
编译:gcc view.c -o view `pkg-config --cflags --libs gtk+-2.0`
*/
#include <gtk/gtk.h>
#include <stdio.h>
#include "mydb.h"
GtkWidget *username_entry,*password_entry;
GtkWidget *vbox;
int write_to_file(char *name)
{
FILE *fp;
char buffer[50];
time_t timep;
char time_buffer[100];
fp=fopen("client.log","a+");
if(fp==NULL)
{
exit(-1);
}
sprintf(buffer,"%s\n",name);
if(fwrite(buffer,sizeof(char),strlen(buffer),fp)<=0)
{
return 0;
}
time (&timep);
sprintf(time_buffer,"%s\n",ctime(&timep));
if(fwrite(time_buffer,sizeof(char),strlen(time_buffer),fp)<=0)
{
return 0;
}
fclose(fp);
return 1;
}
void closeApp(GtkWidget *window,gpointer data)
{
mydb_destory(mysql);
gtk_main_quit();
}
mydb.h:
#include <mysql.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
MYSQL *mysql;
void mydb_init()
{
unsigned int timeout=5;
int ret=0;
mysql=mysql_init(NULL);
if(mysql==NULL)
{
fprintf(stderr,"Mysql_init failed\n");
return;
}
ret=mysql_options(mysql,MYSQL_OPT_CONNECT_TIMEOUT,(const char *)&timeout);
if(ret!=0)
{
fprintf(stderr,"set timeout error\n");
return;
}
mysql=mysql_real_connect(mysql,"localhost","user","passwd","qq",0,NULL,0);
if(mysql){
printf("connection success\n");
}else{
fprintf(stderr,"connection failed\n");
if(mysql_errno(mysql)){
fprintf(stderr,"Connection error %d: %d\n",mysql_errno(mysql),mysql_error(mysql));
}
return;
}
}
int mydb_insert(MYSQL *mysql,void *user,void *password)
{
int ret=0;
/*
int *a=(int)user;
int res=*a;
*/
char* user_data=(char *)user;
char* pswd_data=(char *)password;
char qs[100];
if(mysql==NULL){
fprintf(stderr,"Mysql error\n");
return 0;
}
sprintf(qs,"insert into children(name,password) values('%s','%s')",user_data,pswd_data);
ret=mysql_query(mysql,qs);
if(!ret){
printf("inserted %lu rows\n",(unsigned long)mysql_affected_rows(mysql));
}
else
{
fprintf(stderr,"insert error %d: %s\n",mysql_errno(mysql),mysql_error(mysql));
}
return 1;
}
int mydb_update(MYSQL *mysql,void *user,void *password)
{
int ret=0;
char* user_data=(char *)user;
char* pswd_data=(char *)password;
char qs[100];
if(mysql==NULL){
fprintf(stderr,"Mysql error\n");
return 0;
}
sprintf(qs,"update children set password='$pswd_data' where name='%s'",user_data);
ret=mysql_query(mysql,qs);
if(!ret){
printf("update %lu rows\n",(unsigned long)mysql_affected_rows(mysql));
}
else
{
fprintf(stderr,"update error %d: %s\n",mysql_errno(mysql),mysql_error(mysql));
}
return 1;
}
int mydb_search(MYSQL *mysql,void *data)
{
MYSQL_RES *res_ptr;
MYSQL_ROW sqlrow;
int res;
char *user_data=(char *)data;
const char *tmp='\0';
char qs[100];
if(mysql==NULL)
{
fprintf(stderr,"mysql error\n");
return 0;
}
sprintf(qs,"select name,password from children where name='%s'",user_data);
res=mysql_query(mysql,qs);
if(res)
{
printf("select error:%s\n",mysql_error(mysql));
return 0;
}
else
{
res_ptr=mysql_store_result(mysql);
if(res_ptr){
printf("Search to %lu rows\n",(unsigned long)mysql_num_rows(res_ptr));
while(sqlrow=mysql_fetch_row(res_ptr)){
printf("Fetched data...\n");
tmp=(const char *)&sqlrow[1];
if(strstr(tmp,user_data)==NULL)
{
printf("not exist!\n");
return 0;
}
}
if(mysql_errno(mysql)){
fprintf(stderr,"Retrive error: %s\n",mysql_error(mysql));
}
mysql_free_result(res_ptr);
}
}
return 1;
}
int mydb_test(MYSQL *mysql,const void * username_text,const void * password_text)
{
MYSQL_RES *res_ptr;
const char *username=(char *)username_text;
const char *password=(char *)password_text;
int res;
unsigned long res_num;
char qs[100];
if(mysql==NULL)
{
fprintf(stderr,"mysql error\n");
return 0;
}
sprintf(qs,"select childno from children where name='%s' and password='%s'",username,password);
res=mysql_query(mysql,qs);
if(res)
{
printf("select error:%s\n",mysql_error(mysql));
return 0;
}
else
{
res_ptr=mysql_store_result(mysql);
if(res_ptr){
res_num=(unsigned long)mysql_num_rows(res_ptr);
printf("res_num: %d\n",res_num);
if(res_num==0)
{
return 0;
}
else
{
printf("Search to %lu rows\n",(unsigned long)mysql_num_rows(res_ptr));
}
if(mysql_errno(mysql)){
fprintf(stderr,"Retrive error: %s\n",mysql_error(mysql));
}
}
mysql_free_result(res_ptr);
}
return 1;
}
void mydb_destory(MYSQL *mysql)
{
if(mysql==NULL)
{
fprintf(stderr,"mysql error\n");
return 0;
}
else
{
mysql_close(mysql);
}
}
client.c:
//gcc client.c -o client `pkg-config --cflags --libs gtk+-2.0` -lpthread
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "client.h"
void closeApp(GtkWidget *window,gpointer data)
{
int sendmsg_len=write(socketcon,"quit",strlen("quit"));
if(sendmsg_len<=0)
{
if(write_to_file("write error")==0)
{
exit(-1);
}
exit(-1);
}
pthread_kill(client_thr,SIGKILL);
close(socketcon);
gtk_main_quit();
}
void Clear_Local_message()
{
GtkTextIter start,end;
gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(Send_buffer),&start,&end);/*获得缓冲区开始和结束位置的Iter*/
gtk_text_buffer_delete(GTK_TEXT_BUFFER(Send_buffer),&start,&end);/*删除缓冲区内容*/
}
/*----------------------------------------------------------------------------*/
void Put_Local_message(const gchar *text)
{
GtkTextIter start,end;
gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(Rcv_buffer),&start,&end);/*获得缓冲区开始和结束位置的Iter*/
gtk_text_buffer_insert(GTK_TEXT_BUFFER(Rcv_buffer),&end,"使用者:\n",10);/*插入文本到缓冲区*/
gtk_text_buffer_insert(GTK_TEXT_BUFFER(Rcv_buffer),&end,text,strlen(text));/*插入文本到缓冲区*/
gtk_text_buffer_insert(GTK_TEXT_BUFFER(Rcv_buffer),&end,"\n",1);/*插入文本到缓冲区*/
int sendmsg_len=write(socketcon,text,strlen(text));
if(sendmsg_len<=0)
{
if(write_to_file("write error")==0)
{
exit(-1);
}
exit(-1);
}
}
/*----------------------------------------------------------------------------*/
void Show_Err(char *err)
{
GtkTextIter start,end;
gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(Rcv_buffer),&start,&end);
gtk_text_buffer_insert(GTK_TEXT_BUFFER(Rcv_buffer),&end,err,strlen(err));
}
/*----------------------------------------------------------------------------*/
/*发送函数----------------------------------------------------------------------*/
void on_send(GtkButton *SaveButton, GtkWidget *Send_textview)/*保存按钮的回调函数,每当‘保存’按钮被按下的时候,都会触发这个函数*/
{
GtkTextIter start,end;/*定义迭代器起点终点*/
gchar *S_text,*R_text;/*定义文字存储变量*/
gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(Send_buffer),&start,&end);
S_text = gtk_text_buffer_get_text(GTK_TEXT_BUFFER(Send_buffer),&start,&end,FALSE);
R_text = S_text;/*把发送文本交换到接收文本*/
if(strcmp(R_text,"")!=0)
{
//Get_Local_message();
Clear_Local_message();
Put_Local_message(R_text);
}
else
{
Show_Err("消息不能为空...!\n");
}
free(R_text);
//free(S_text);
}
/*----------------------------------------------------------------------------*/
/*关闭函数---------------------------------------------------------------------*/
void on_close(GtkButton *CloseButton,GtkWidget *Send_textview)
{
int sendmsg_len=write(socketcon,"quit",strlen("quit"));
if(sendmsg_len<=0)
{
if(write_to_file("write error")==0)
{
exit(-1);
}
exit(-1);
}
pthread_kill(client_thr,SIGKILL);
close(socketcon);
gtk_main_quit();
}
/*----------------------------------------------------------------------------*/
/*主函数-----------------------------------------------------------------------*/
int main(int argc, char *argv[])
{
/*主函数变量声明区*/
GtkWidget *window/*定义主窗口*/,
*Send_scrolled_win/*定义发送滚动窗口*/,
*Rcv_scrolled_win/*定义接收滚动窗口*/;
GtkWidget *vbox/*定义垂直盒子*/;
GtkWidget *Button_Box/*定义按钮盒*/,
*SendButton/*定义发送按钮*/,
*CloseButton/*定义关闭按钮*/;
GtkWidget *hseparator/*定义水平分割线*/;
//*panel_v/*定义垂直分割面板*/,
//*panel_h/*定义水平分割面板*/;
/*------------------------------连接服务端------------------------*/
if(write_to_file("start socket")==0)
{
exit(-1);
}
socketcon=socket(AF_INET,SOCK_STREAM,0);
if(socketcon<0)
{
if(write_to_file("socket error")==0)
{
exit(-1);
}
exit(-1);
}
struct sockaddr_in server_addr;
server_addr.sin_family=AF_INET;
server_addr.sin_addr.s_addr=inet_addr(ip);
server_addr.sin_port=htons(port);
/*测试*/
printf("客户端的套接字:%d\n",socketcon);
int res_con=connect(socketcon,(struct sockaddr*)(&server_addr),sizeof(struct sockaddr));
if(res_con!=0)
{
if(write_to_file("connect error")==0)
{
exit(-1);
}
exit(-1);
}
printf("连接成功!");
if(write_to_file("连接成功")==0)
{
exit(-1);
}
/*---------------------------------------------------------------*/
/*--------------------客户端的接受消息的线程函数的执行----------------*/
if(pthread_create(&client_thr,NULL,fun_clientreceive,&socketcon)!=0)
{
if(write_to_file("pthread_create error")==0)
{
exit(-1);
}
exit(-1);
}
sleep(1);
/*---------------------------------------------------------------*/
/*-------------------------这是关于窗口的初始化---------------------*/
gtk_init(&argc,&argv);/*GTK初始化*/
/*------------------------------绘制主窗口----------------------------*/
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);/*生成主窗口*/
g_signal_connect(G_OBJECT(window),"destroy",GTK_SIGNAL_FUNC(closeApp),NULL);
//g_singal_connect(G_OBJECT(window),"destroy",GTK_SIGNAL_FUNC(closeApp),NULL);
// g_signal_connect(G_OBJECT(window),"delete_event",G_CALLBACK(gtk_main_quit),NULL);/*连接信号,关闭窗口*/
gtk_window_set_title(GTK_WINDOW(window),"聊天窗口");/*设置主窗口标题*/
gtk_container_set_border_width(GTK_CONTAINER(window),10);/*设置主窗口边框*/
gtk_widget_set_size_request(window,400,300);/*设置主窗口初始化大小*/
gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER);/*设置主窗口初始位置*/
/*------------------------------设置Send_text view-------------------------*/
Send_textview = gtk_text_view_new();/*生成text view*/
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(Send_textview),GTK_WRAP_WORD);/*处理多行显示的模式*/
gtk_text_view_set_justification(GTK_TEXT_VIEW(Send_textview),GTK_JUSTIFY_LEFT);/*控制文字显示方向的,对齐方式*/
gtk_text_view_set_editable(GTK_TEXT_VIEW(Send_textview),TRUE);/*允许text view内容修改*/
gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(Send_textview),TRUE);/*设置光标可见*/
gtk_text_view_set_pixels_above_lines(GTK_TEXT_VIEW(Send_textview),5);/*设置上行距*/
gtk_text_view_set_pixels_below_lines(GTK_TEXT_VIEW(Send_textview),5);/*设置下行距*/
gtk_text_view_set_pixels_inside_wrap(GTK_TEXT_VIEW(Send_textview),5);/*设置词距*/
gtk_text_view_set_left_margin(GTK_TEXT_VIEW(Send_textview),10);/*设置左边距*/
gtk_text_view_set_right_margin(GTK_TEXT_VIEW(Send_textview),10);/*设置右边距*/
Send_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(Send_textview));/*返回text view被显示的buffer*/
/*------------------------------设置Rcv_text view-------------------------*/
Rcv_textview = gtk_text_view_new();/*生成text view*/
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(Rcv_textview),GTK_WRAP_WORD);/*处理多行显示的模式*/
gtk_text_view_set_justification(GTK_TEXT_VIEW(Rcv_textview),GTK_JUSTIFY_LEFT);/*控制文字显示方向的,对齐方式*/
gtk_text_view_set_editable(GTK_TEXT_VIEW(Rcv_textview),TRUE);/*允许text view内容修改*/
gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(Rcv_textview),TRUE);/*设置光标可见*/
gtk_text_view_set_pixels_above_lines(GTK_TEXT_VIEW(Rcv_textview),5);/*设置上行距*/
gtk_text_view_set_pixels_below_lines(GTK_TEXT_VIEW(Rcv_textview),5);/*设置下行距*/
gtk_text_view_set_pixels_inside_wrap(GTK_TEXT_VIEW(Rcv_textview),5);/*设置词距*/
gtk_text_view_set_left_margin(GTK_TEXT_VIEW(Rcv_textview),10);/*设置左边距*/
gtk_text_view_set_right_margin(GTK_TEXT_VIEW(Rcv_textview),10);/*设置右边距*/
gtk_text_view_set_editable(GTK_TEXT_VIEW(Rcv_textview),FALSE);/*设置接收文字区不可被编辑*/
Rcv_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(Rcv_textview));/*返回text view被显示的buffer*/
/*------------------------------设置发送窗口滚动条-------------------------------*/
Send_scrolled_win = gtk_scrolled_window_new(NULL,NULL);/*生成滚动条的窗口*/
gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(Send_scrolled_win),Send_textview);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(Send_scrolled_win),GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC);/*滚动条属性*/
/*------------------------------设置接收窗口滚动条-------------------------------*/
Rcv_scrolled_win = gtk_scrolled_window_new(NULL,NULL);/*生成滚动条的窗口*/
gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(Rcv_scrolled_win),Rcv_textview);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(Rcv_scrolled_win),GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC);/*滚动条属性*/
/*------------------------------设置垂直盒子------------------------------*/
vbox = gtk_vbox_new(FALSE,0);/*生成一个垂直排布的盒子*/
/*------------------------------设置发送按钮------------------------------*/
SendButton = gtk_button_new_with_label("发送");/*生成发送按钮*/
g_signal_connect(G_OBJECT(SendButton),"clicked",G_CALLBACK(on_send),(gpointer)Send_textview);/*给按钮加上回调函数*/
/*------------------------------设置关闭按钮------------------------------*/
CloseButton = gtk_button_new_with_label("关闭");/*生成关闭按钮*/
g_signal_connect(G_OBJECT(CloseButton),"clicked",G_CALLBACK(on_close),(gpointer)Send_textview);
/*------------------------------设置按钮盒子------------------------------*/
Button_Box = gtk_hbutton_box_new();/*生成按钮盒*/
gtk_box_set_spacing(GTK_BOX(Button_Box),1);/*按钮之间的间隔*/
gtk_button_box_set_layout(GTK_BUTTON_BOX(Button_Box),GTK_BUTTONBOX_END);/*按钮盒内部布局,风格是尾对齐*/
gtk_container_set_border_width(GTK_CONTAINER(Button_Box),5);/*边框宽*/
/*------------------------------设置分割线--------------------------------*/
hseparator = gtk_hseparator_new();
/*------------------------------添加到容器--------------------------------*/
gtk_container_add(GTK_CONTAINER(vbox),Rcv_scrolled_win);/*包装滚动条窗口到主窗口*/
gtk_container_add(GTK_CONTAINER(vbox),hseparator);/*加入一条分割线*/
gtk_container_add(GTK_CONTAINER(vbox),Send_scrolled_win);/*包装滚动条窗口到主窗口*/
gtk_container_add(GTK_CONTAINER(vbox),Button_Box);/*把按钮盒包装到vbox中*/
gtk_box_pack_start(GTK_BOX(Button_Box),CloseButton,TRUE,TRUE,5);/*把关闭按钮包装到按钮盒里面去*/
gtk_box_pack_start(GTK_BOX(Button_Box),SendButton,TRUE,TRUE,5);/*把发送按钮包装到按钮盒里面去*/
gtk_container_add(GTK_CONTAINER(window),vbox);/*将盒子封装到主窗口中去*/
/*------------------------------显示所有东西------------------------------*/
gtk_widget_show_all(window);/*显示所有东西*/
gtk_main();/*主循环*/
/*-----------------------------等待线程退出-------------------------------*/
char *client_message;
int res=1;
if(pthread_join(client_thr,(void *)&client_message)==0)
{
printf("%s\n",client_message);
}
else
{
if(write_to_file("pthread_join error")==0)
{
exit(-1);
}
exit(-1);
}
/*----------------------------------------------------------------------*/
pthread_kill(client_thr,SIGKILL);
return 0;/*退出程序*/
}
client.h:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/signal.h>
#include <gtk/gtk.h>
#define MAXLEN 1024
typedef struct mysocketinfo{
int socketcon;
unsigned long ipaddr;
unsigned short port;
}_mysocketinfo;
const char *ip="127.0.0.1";
const int port=8888;
int socketcon;
/*---------------------------------客户端接受线程---------------------------------*/
pthread_t client_thr;
/*------------------------------------------------------------------------------*/
/*全局变量声明区-----------------------------------------------------------------*/
GtkWidget *Send_textview/*定义发送文本区*/,
*Rcv_textview/*定义接收文本区*/;
GtkTextBuffer *Send_buffer/*定义发送文本缓冲区*/,
*Rcv_buffer/*定义接收文本缓冲区*/;
/*----------------------------------------------------------------------------*/
int write_to_file(char *name)
{
FILE *fp;
char buffer[50];
time_t timep;
char time_buffer[100];
fp=fopen("client.log","a+");
if(fp==NULL)
{
exit(-1);
}
sprintf(buffer,"%s\n",name);
if(fwrite(buffer,sizeof(char),strlen(buffer),fp)<=0)
{
return 0;
}
time (&timep);
sprintf(time_buffer,"%s\n",ctime(&timep));
if(fwrite(time_buffer,sizeof(char),strlen(time_buffer),fp)<=0)
{
return 0;
}
fclose(fp);
return 1;
}
void *fun_clientreceive(void *_socketcon)
{
char buffer[MAXLEN];
int socketcon=*((int *)_socketcon);
while(1)
{
memset(buffer,'\0',sizeof(buffer));
int buffer_length=read(socketcon,buffer,MAXLEN-1);
if(buffer_length<=0)
{
if(write_to_file("client read error")==0)
{
exit(-1);
}
exit(-1);
}
else
{
GtkTextIter start,end;/*定义迭代器起点终点*/
gchar *S_text,*R_text;/*定义文字存储变量*/
gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(Rcv_buffer),&start,&end);
gtk_text_buffer_insert(GTK_TEXT_BUFFER(Rcv_buffer),&end,"服务器:\n",10);/*插入文本到缓冲区*/
gtk_text_buffer_insert(GTK_TEXT_BUFFER(Rcv_buffer),&end,buffer,strlen(buffer));/*插入文本到缓冲区*/
gtk_text_buffer_insert(GTK_TEXT_BUFFER(Rcv_buffer),&end,"\n",1);/*插入文本到缓冲区*/
}
}
pthread_exit("线程退出!");
}
server.c:
#include "server.h"
int checkthriskill(pthread_t thr)
{
//1存在,0不存在
int res=1;
//判断线程是否存在
int kill_rc=pthread_kill(thr,0);
if(kill_rc == ESRCH)
{
printf("ID为%d的线程不存在或者已经退出。\n",(unsigned int)thr);
res=0;
}
else if(kill_rc == EINVAL)
{
printf("发送信号非法。\n");
res=0;
}
else
{
printf("ID为%d的线程目前仍然存活。\n",(unsigned int)thr);
res=1;
}
return res;
}
//删除杀死的线程
int delete_client(void *fp,int num)
{
int i=0;
pthread_t *ps=(pthread_t *)fp;
if(num<1)
{
return 0;
}
for(i=num;i<=arr;i++)
{
ps[i]=ps[i+1];
arrconsocket[i]=arrconsocket[i+1];
}
return 1;
}
int main()
{
int service_socket=socket(AF_INET,SOCK_STREAM,0);//创建服务端的套接字
if(service_socket<0)//如果创建套接字失败了
{
if(write_to_file("server socket error")==0)
{
exit(-1);
}
exit(-1);
}
struct sockaddr_in addr;//套接字地址结构
addr.sin_family=AF_INET;
addr.sin_port=htons(port);
addr.sin_addr.s_addr=inet_addr(ip);
if(bind(service_socket,(struct sockaddr*)&addr,sizeof(addr))<0)//连接套接字结构和套接字
{
if(write_to_file("bind error")==0)
{
exit(-1);
}
exit(-1);
}
int listen_socket=listen(service_socket,10);//监听套接字
if(listen_socket<0)//失败的处理
{
if(write_to_file("listen error")==0)
{
exit(-1);
}
exit(-1);
}
pthread_t thraccept;//创建的线程数组
//pthread_create创建线程(实际上就是确定调用该线程函数的入口点),在线程创建以后,就开始运行相关的线程函数
if(pthread_create(&thraccept,NULL,fun_thraccepthander,&service_socket)!=0)
{
if(write_to_file("pthread_create error")==0)
{
exit(-1);
}
exit(-1);
}
sleep(1);
while(1)
{
int i=1;
for(i=1;i<=arr;i++)
{
if(checkthriskill(arrthrreceiveclient[i])==0)
{
printf("have a thread is killed\n");
if(delete_client((void*)(&arrthrreceiveclient),i)==0)
{
if(write_to_file("delete_client error")==0)
{
exit(-1);
}
exit(-1);
}
--arr;
}
}
printf("在线人数:%d\n",arr);
if(arr<=0)
{
printf("没有客户端连接\n");
}
else
{
int i=0;
char buf[MAXLEN];
ssize_t size=0;
memset(buf,'\0',MAXLEN);
size=read(STDIN_FILENO,buf,sizeof(buf));
if(size>0)
{
buf[size]='\0';
}
else
{
if(write_to_file("read error")==0)
{
exit(-1);
}
break;
}
for(i=1;i<=arr;i++)
{
int sendmsg_len=write(arrconsocket[i].socketcon,buf,size);
if(sendmsg_len>0)
{
printf("向客户端%s:%d发送成功\n",arrconsocket[i].ipaddr,arrconsocket[i].port);
}
else
{
printf("向客户端%s:%d发送失败\n",arrconsocket[i].ipaddr,arrconsocket[i].port);
}
}
}
sleep(1);
}
if(arr>=1)
{
char *message;
int res=1;
printf("等待线程退出\n");
if((res=pthread_join(thraccept,(void*)&message))==0)
{
printf("%s\n",message);
}
else
{
if(write_to_file("pthread_join error")==0)
{
exit(-1);
}
exit(-1);
}
}
else
{
printf("没有线程\n");
}
close(service_socket);
pthread_kill(thraccept,SIGKILL);
return(0);
}
server.h:
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
#include <string.h>
#include <arpa/inet.h>
#include <errno.h>
#include <time.h>
#define MAXLEN 1024
#define MAXTHR 10
const int port=8888;
const char *ip="127.0.0.1";
typedef struct mysocketinfo{
int socketcon;
char *ipaddr;
uint16_t port;
}_mysocketinfo;
pthread_t arrthrreceiveclient[10];
struct mysocketinfo arrconsocket[10];
static int arr=0;
int exit_thr(void *_socketcon)
{
int socketcon=*((int *)_socketcon);
int i=0,k=0;
printf("线程退出\n");
for(i=0;i<=arr;i++){
if(arrconsocket[i].socketcon==socketcon)
{
for(k=i;k<=arr;k++)
{
arrconsocket[k]=arrconsocket[k+1];
arrthrreceiveclient[k]=arrthrreceiveclient[k+1];
}
}
}
}
/*写入日志文件*/
int write_to_file(char *name)
{
FILE *fp;
char buffer[50];
time_t timep;
char time_buffer[100];
fp=fopen("server.log","a+");
if(fp==NULL)
{
exit(-1);
}
sprintf(buffer,"%s\n",name);
if(fwrite(buffer,sizeof(char),strlen(buffer),fp)<=0)
{
return 0;
}
time (&timep);
sprintf(time_buffer,"%s\n",ctime(&timep));
if(fwrite(time_buffer,sizeof(char),strlen(time_buffer),fp)<=0)
{
return 0;
}
fclose(fp);
return 1;
}
//接收消息函数
void *fun_thrreceivehandler(void *socketcon){
char buffer[MAXLEN];
int buffer_length;
int socketcon1;
socketcon1=*((int*)socketcon);
while(1){
memset(buffer,'\0',sizeof(buffer));//或者使用函数bzero(buffer,20);
printf("接收套接字:%d\n",socketcon1);
buffer_length=read(socketcon1,buffer,MAXLEN-1);
if(buffer_length<0)
{
if(write_to_file("read from client error")==0)
{
exit(-1);
}
exit(-1);
}/*客户端的退出没有捕获到,此DUG待处理*/
else if(strncmp(buffer,"NULL",4)==0)
{
fprintf(stdout,"套接字:%d close\n",socketcon1);
exit_thr(&socketcon1);
arr--;
pthread_exit("线程退出!");
break;
}
if(strncmp(buffer,"quit",4)==0)
{
fprintf(stdout,"套接字:%d close\n",socketcon1);
exit_thr(&socketcon1);
arr--;
pthread_exit("线程退出!");
break;
}
//printf("buffer:%s\n",buffer);
buffer[buffer_length]='\0';
printf("客户端%d:%s\n",socketcon1,buffer);
/*------------------------这是通过服务端向每个客户端写入数据-------------------*/
int i=0;
for(i=1;i<=arr;i++)
{
if(arrconsocket[i].socketcon!=socketcon1)
{
/*------------------------这是传递客户端的名字-------------------------------*/
char client_name[50];
sprintf(client_name,"中转%s--%d--->%s",arrconsocket[i].ipaddr,arrconsocket[i].port,buffer);
/*------------------------------------------------------------------------*/
int sendmsg_len=write(arrconsocket[i].socketcon,client_name,sizeof(client_name));
if(sendmsg_len>0)
{
printf("向客户端%s:%d发送成功\n",arrconsocket[i].ipaddr,arrconsocket[i].port);
}
else
{
printf("向客户端%s:%d发送失败\n",arrconsocket[i].ipaddr,arrconsocket[i].port);
}
}
}
/*------------------------------------------------------------------------*/
sleep(1);
}
printf("接受数据线程结束\n");
}
//处理acceot
void *fun_thraccepthander(void *socketlisten){
char buf[MAXLEN];
ssize_t size;
int sockaddr_in_size=sizeof(struct sockaddr_in);//sockaddr_in结构体的大小
int socklisten1=*((int*)socketlisten);
int socketcon;
pthread_t thrreceive=0;
struct sockaddr_in client_addr;
char accept_message[50];
while(1){
socketcon=accept(socklisten1,(struct sockaddr*)(&client_addr),(socklen_t *)(&sockaddr_in_size));
if(socketcon<0)
{
if(write_to_file("accept error")==0)
{
exit(-1);
}
}
else{
if(write_to_file("accept success")==0)
{
exit(-1);
}
sprintf(accept_message,"ip: %s,port: %d",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
if(write_to_file(accept_message)==0)
{
exit(-1);
}
}
printf("在线人数:%d\n",++arr);
printf("连接客户端的套接字:%d\n",socketcon);
arrconsocket[arr].socketcon=socketcon;
arrconsocket[arr].ipaddr=inet_ntoa(client_addr.sin_addr);
arrconsocket[arr].port=client_addr.sin_port;
//接收的消息
if(pthread_create(&thrreceive,NULL,fun_thrreceivehandler,&socketcon)!=0)
{
if(write_to_file("pthread_create error")==0)
{
exit(-1);
}
break;
}
arrthrreceiveclient[arr]=thrreceive;
sleep(1);
}
char *message;
int res=1;
printf("等待接受的子线程退出\n");
if((res=pthread_join(thrreceive,(void*)&message))==0)
{
printf("%s\n",message);
}
else
{
if(write_to_file("pthread_join error")==0)
{
exit(-1);
}
exit(-1);
}
}
Makefile文件:
all: app client server
# If using Redhat 8+ or Fedora, may need to add -L/usr/lib/mysql to link to MySQL.
#gcc -o app -I/usr/include/mysql main.c -L/usr/lib64/mysql -lmysqlclient `pkg-config --cflags --libs gtk+-2.0`
app: main.c view.h mydb.h
#gcc main.c -o app `pkg-config --cflags --libs gtk+-2.0`
gcc -o app -I/usr/include/mysql main.c -L/usr/lib64/mysql -lmysqlclient `pkg-config --cflags --libs gtk+-2.0`
client: client.c client.h
gcc client.c -o client `pkg-config --cflags --libs gtk+-2.0` -lpthread
server: server.c server.h
gcc server.c -o server -lpthread
clean:
rm -f app
rm -f client
rm -f server
附上效果图:
技术不分国界