本程序的通信是基于UDP协议的传输实现
服务器端:
server.h
/*********************************** * server.h * * the header files and functions * ***********************************/ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <stdio.h> #include <errno.h> #include <stdlib.h> #include <string.h> #include <semaphore.h> #include <unistd.h> #include <pthread.h> #include <arpa/inet.h> #define bool _Bool #define true 1 #define false 0 #define PORT 8888 #define MAXSIZE 1024 void *recv_func(void *arg); int build_socket(); void send_text(void); void send_func(const char *); void show_remote_text(char rcvd_mess[]); void show_err(char *err); void clean_send_text(void); void startup(void);
se_sock.c
/************************************************ * se_sock.c * * function: * * create a socket * * create a new thread,for receive function * * send message * ************************************************/ #include "server.h" socklen_t len; bool from_host;//表示客户端是否已经向本服务器发送来信息 int sockfd; struct sockaddr_in saddr,caddr;//saddr表示本地服务器地址信息,caddr用于保存向本服务器发送信息的主机地址信息 int build_socket() { int res; pthread_t recv_thread; pthread_attr_t thread_attr; len=sizeof(caddr); /* Set status of thread */ res=pthread_attr_init(&thread_attr); if(res!=0) { show_err("Setting detached attribute failed"); exit(EXIT_FAILURE); } /* Create a socket */ if((sockfd=socket(AF_INET,SOCK_DGRAM,0))<0) { show_err("Socket Error"); exit(1); } bzero(&saddr,sizeof(struct sockaddr)); saddr.sin_family=AF_INET; saddr.sin_addr.s_addr=htonl(INADDR_ANY); saddr.sin_port=htons(PORT); if(bind(sockfd,(struct sockaddr *)&saddr,sizeof(struct sockaddr_in))==-1) { show_err("Bind Error"); exit(1); } /* Set the status of thread,don't wait for return of the subthread */ res=pthread_attr_setdetachstate(&thread_attr,PTHREAD_CREATE_DETACHED); if(res!=0) { show_err("Setting detached attribute failed"); exit(EXIT_FAILURE); } /* Create a sub thread,call recv_func() */ res=pthread_create(&recv_thread,&thread_attr,recv_func,NULL); if(res!=0) { show_err("Thread create error"); exit(EXIT_FAILURE); } /* Callback the attribute of thread */ (void)pthread_attr_destroy(&thread_attr); } /* Receive function */ void *recv_func(void *arg) { char recv_text[MAXSIZE]; while(1) { /* To Receive message from client and get the address infomation */ if(recvfrom(sockfd,recv_text,sizeof(recv_text),0,(struct sockaddr*)&caddr,&len)<0) { show_err("server recv error"); exit(1); } if( from_host==false ) from_host=true; show_remote_text(recv_text); } } /* Send function,send message to client */ void send_func(const char * send_text) { /* If there is no text,continue */ if(strlen(send_text)==1) return; if( !from_host ) show_err("Unknown the client's address infomation/nPlease wait the client to connect you first !/n"); /* Send message */ if(from_host && sendto(sockfd,send_text,MAXSIZE,0,(struct sockaddr*)&caddr,len)<0) { show_err("S send error"); exit(1); } }
server.c
/************************************************* * server.c * * create the server window * * send message to client * *************************************************/ #include "server.h" #include<gtk/gtk.h> bool socket_start; GtkTextBuffer *show_buffer,*input_buffer; void quit_win(GtkWidget *,gpointer); int main(int argc,char **argv) { GtkWidget *window; GtkWidget *show_text,*input_text; GtkWidget *send_button,*quit_button,*cls_button,*start_button; GtkWidget *hbox,*vbox; GtkWidget *scrolled1,*scrolled2; GtkWidget *space_label; gtk_init(&argc,&argv); window=gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window),"Server"); gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); gtk_window_set_default_size(GTK_WINDOW(window),430,320); /* "quit" button */ g_signal_connect(GTK_OBJECT(window),"destroy",GTK_SIGNAL_FUNC(quit_win),NULL); space_label=gtk_label_new(" "); /* set button */ send_button=gtk_button_new_with_label("Send"); quit_button=gtk_button_new_with_label("Close"); cls_button=gtk_button_new_with_label("Clear"); start_button=gtk_button_new_with_label("Startup"); /* set textbox */ show_text=gtk_text_view_new(); input_text=gtk_text_view_new(); /* get the buffer of textbox */ show_buffer=gtk_text_view_get_buffer(GTK_TEXT_VIEW(show_text)); input_buffer=gtk_text_view_get_buffer(GTK_TEXT_VIEW(input_text)); /* set textbox to diseditable */ gtk_text_view_set_editable(GTK_TEXT_VIEW(show_text),FALSE); /* scroll window */ scrolled1=gtk_scrolled_window_new(NULL,NULL); scrolled2=gtk_scrolled_window_new(NULL,NULL); /* create a textbox */ gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled1),show_text); gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled2),input_text); /* setting of window */ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled1),GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled2),GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC); hbox=gtk_hbox_new(FALSE,2); vbox=gtk_vbox_new(FALSE,2); /* click quit to call quit_win*/ g_signal_connect(GTK_OBJECT(quit_button),"clicked",GTK_SIGNAL_FUNC(quit_win),NULL); /* click to clear input screen*/ g_signal_connect(GTK_OBJECT(cls_button),"clicked",GTK_SIGNAL_FUNC(clean_send_text),NULL); /* click Start to build socket*/ g_signal_connect(GTK_OBJECT(start_button),"clicked",GTK_SIGNAL_FUNC(startup),NULL); /* create window */ gtk_box_pack_start(GTK_BOX(hbox),start_button,FALSE,FALSE,2); gtk_box_pack_start(GTK_BOX(hbox),space_label,TRUE,TRUE,2); gtk_box_pack_start(GTK_BOX(hbox),send_button,FALSE,FALSE,2); gtk_box_pack_start(GTK_BOX(hbox),cls_button,FALSE,FALSE,2); gtk_box_pack_start(GTK_BOX(hbox),quit_button,FALSE,FALSE,2); gtk_box_pack_start(GTK_BOX(vbox),scrolled1,TRUE,TRUE,2); gtk_box_pack_start(GTK_BOX(vbox),scrolled2,FALSE,FALSE,2); gtk_box_pack_start(GTK_BOX(vbox),hbox,FALSE,FALSE,2); gtk_container_add(GTK_CONTAINER(window),vbox); /* click send button ,then call send_text*/ gtk_signal_connect(GTK_OBJECT(send_button),"clicked",GTK_SIGNAL_FUNC(send_text),NULL); gtk_widget_show_all(window); gtk_main(); return 0; } /* show the input text */ void show_local_text(const gchar* text) { GtkTextIter start,end; gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(show_buffer),&start,&end);/*获得缓冲区开始和结束位置的Iter*/ gtk_text_buffer_insert(GTK_TEXT_BUFFER(show_buffer),&end,"Me:/n",4);/*插入文本到缓冲区*/ gtk_text_buffer_insert(GTK_TEXT_BUFFER(show_buffer),&end,text,strlen(text));/*插入文本到缓冲区*/ gtk_text_buffer_insert(GTK_TEXT_BUFFER(show_buffer),&end,"/n",1);/*插入文本到缓冲区*/ } /* clean the input text */ void clean_send_text() { GtkTextIter start,end; gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(input_buffer),&start,&end);/*获得缓冲区开始和结束位置的Iter*/ gtk_text_buffer_delete(GTK_TEXT_BUFFER(input_buffer),&start,&end);/*插入到缓冲区*/ } /* get the input text,and send it */ void send_text() { GtkTextIter start,end; gchar *text; /* Socket creating has succeed ,so send message */ text=(gchar *)malloc(MAXSIZE); if(text==NULL) { printf("Malloc error!/n"); exit(1); } /* get text */ gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(input_buffer),&start,&end); text=gtk_text_buffer_get_text(GTK_TEXT_BUFFER(input_buffer),&start,&end,FALSE); /* If there is no input,do nothing but return */ if(strcmp(text,"")!=0) { send_func(text); clean_send_text(); show_local_text(text); } else show_err("The message can not be empty .../n"); free(text); } void startup(void) { if( !socket_start ) { build_socket(); socket_start=true; return; } show_err("The server has been started !/n"); } /* show errors such as "no input","haven't create sockt" etc. */ void show_err(char *err) { GtkTextIter start,end; gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(show_buffer),&start,&end);/*获得缓冲区开始和结束位置的Iter*/ gtk_text_buffer_insert(GTK_TEXT_BUFFER(show_buffer),&end,err,strlen(err)); } /* show the received message */ void show_remote_text(char rcvd_mess[]) { GtkTextIter start,end; gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(show_buffer),&start,&end);/*获得缓冲区开始和结束位置的Iter*/ gtk_text_buffer_insert(GTK_TEXT_BUFFER(show_buffer),&end,"Client:/n",8);/*插入文本到缓冲区*/ gtk_text_buffer_insert(GTK_TEXT_BUFFER(show_buffer),&end,rcvd_mess,strlen(rcvd_mess));/*插入文本到缓冲区*/ gtk_text_buffer_insert(GTK_TEXT_BUFFER(show_buffer),&end,"/n",1);/*插入换行到缓冲区*/ } /* quit */ void quit_win(GtkWidget *window,gpointer data) { gtk_main_quit(); }
客户端
client.h
/*********************************** * client.h * * the header files and functions * ***********************************/ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <errno.h> #include <unistd.h> #include <pthread.h> #define PORT 8888 #define MAXSIZE 1024 int build_socket(const char *); void send_text(void); void send_func(const char *); void *recv_func(void *); void show_remote_text(char rcvd_mess[]); void clean_send_text(void); void show_err(char *err);
cl_sock.c
/************************************************ * cl_sock.c * * function: * * create a socket * * create a new thread,for receive function * * send message * ************************************************/ #include "client.h" int sockfd; struct sockaddr_in saddr; int build_socket(const char *serv_ip) { int res; pthread_t recv_thread; pthread_attr_t thread_attr; /* set status of thread */ res=pthread_attr_init(&thread_attr); if(res!=0) { perror("Setting detached attribute failed"); exit(EXIT_FAILURE); } sockfd=socket(AF_INET,SOCK_DGRAM,0); /* create a socket */ if(sockfd==-1) { perror("Socket Error"); exit(1); } bzero(&saddr,sizeof(saddr)); saddr.sin_family=AF_INET; saddr.sin_port=htons(PORT); res=inet_pton(AF_INET,serv_ip,&saddr.sin_addr); if(res==0){ /* the serv_ip is invalid */ return 1; } else if(res==-1){ return -1; } /* set the stats of thread:means do not wait for the return value of subthread */ res=pthread_attr_setdetachstate(&thread_attr,PTHREAD_CREATE_DETACHED); if(res!=0) { perror("Setting detached attribute failed"); exit(EXIT_FAILURE); } /* Create a thread,to process the receive function. */ res=pthread_create(&recv_thread,&thread_attr,&recv_func,NULL); if(res!=0) { perror("Thread create error"); exit(EXIT_FAILURE); } /* callback the attribute */ (void)pthread_attr_destroy(&thread_attr); return 0; } /* send function */ void send_func(const char *text) { int n; socklen_t len=sizeof(saddr); n=sendto(sockfd,text,MAXSIZE,0,(const struct sockaddr*)&saddr,len); if(n<0) { perror("S send error"); exit(1); } } /* a new thread,to receive message */ void *recv_func(void *arg) { char rcvd_mess[MAXSIZE]; while(1) { bzero(rcvd_mess,MAXSIZE); if(recvfrom(sockfd,rcvd_mess,MAXSIZE,0,NULL,NULL)<0) /*阻塞直到收到客户端发的消息*/ { perror("server recv error"); exit(1); } show_remote_text(rcvd_mess); } }
client.c
/********************************* * Client.c * * Function: * * create the chat window * *********************************/ #include "client.h" #include <gtk/gtk.h> int issucceed=-1; GtkTextBuffer *show_buffer,*input_buffer; void get_ip(GtkWidget *,gpointer); void quit_win(GtkWidget *,gpointer); int main(int argc,char **argv) { GtkWidget *window; GtkWidget *show_text,*input_text,*ip_text; GtkWidget *ip_label,*space_label; GtkWidget *link_button,*send_button,*quit_button,*cls_button; GtkWidget *hbox,*vbox; GtkWidget *scrolled1,*scrolled2; gtk_init(&argc,&argv); window=gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window),"Client"); gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); gtk_window_set_default_size(GTK_WINDOW(window),430,320); /* "quit" button */ g_signal_connect(GTK_OBJECT(window),"destroy",GTK_SIGNAL_FUNC(quit_win),NULL); ip_label=gtk_label_new("IP:"); space_label=gtk_label_new(" "); /* set button */ link_button=gtk_button_new_with_label("Connect"); send_button=gtk_button_new_with_label("Send"); quit_button=gtk_button_new_with_label("Close"); cls_button=gtk_button_new_with_label("Clear"); /* set textbox */ ip_text=gtk_entry_new(); show_text=gtk_text_view_new(); input_text=gtk_text_view_new(); /* set length of IP box */ gtk_entry_set_max_length(GTK_ENTRY(ip_text),15); /* get the buffer of textbox */ show_buffer=gtk_text_view_get_buffer(GTK_TEXT_VIEW(show_text)); input_buffer=gtk_text_view_get_buffer(GTK_TEXT_VIEW(input_text)); /* set textbox to diseditable */ gtk_text_view_set_editable(GTK_TEXT_VIEW(show_text),FALSE); /* scroll window */ scrolled1=gtk_scrolled_window_new(NULL,NULL); scrolled2=gtk_scrolled_window_new(NULL,NULL); /* create a textbox */ gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled1),show_text); gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled2),input_text); /* setting of window */ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled1),GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled2),GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC); hbox=gtk_hbox_new(FALSE,2); vbox=gtk_vbox_new(FALSE,2); /* click quit to call quit_win*/ g_signal_connect(GTK_OBJECT(quit_button),"clicked",GTK_SIGNAL_FUNC(quit_win),NULL); /* click "connect" to call get_ip */ g_signal_connect(GTK_OBJECT(link_button),"clicked",GTK_SIGNAL_FUNC(get_ip),ip_text); /* click to clear input screen*/ g_signal_connect(GTK_OBJECT(cls_button),"clicked",GTK_SIGNAL_FUNC(clean_send_text),NULL); /* create window */ gtk_box_pack_start(GTK_BOX(hbox),ip_label,FALSE,FALSE,2); gtk_box_pack_start(GTK_BOX(hbox),ip_text,FALSE,FALSE,2); gtk_box_pack_start(GTK_BOX(hbox),link_button,FALSE,FALSE,2); gtk_box_pack_start(GTK_BOX(hbox),space_label,TRUE,TRUE,2); gtk_box_pack_start(GTK_BOX(hbox),send_button,FALSE,FALSE,2); gtk_box_pack_start(GTK_BOX(hbox),cls_button,FALSE,FALSE,2); gtk_box_pack_start(GTK_BOX(hbox),quit_button,FALSE,FALSE,2); gtk_box_pack_start(GTK_BOX(vbox),scrolled1,TRUE,TRUE,2); gtk_box_pack_start(GTK_BOX(vbox),scrolled2,FALSE,FALSE,2); gtk_box_pack_start(GTK_BOX(vbox),hbox,FALSE,FALSE,2); gtk_container_add(GTK_CONTAINER(window),vbox); /* click send button ,then call send_text*/ gtk_signal_connect(GTK_OBJECT(send_button),"clicked",GTK_SIGNAL_FUNC(send_text),NULL); gtk_widget_show_all(window); gtk_main(); return 0; } /* show the input text */ void show_local_text(const gchar* text) { GtkTextIter start,end; gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(show_buffer),&start,&end);/*获得缓冲区开始和结束位置的Iter*/ gtk_text_buffer_insert(GTK_TEXT_BUFFER(show_buffer),&end,"Me:/n",4);/*插入文本到缓冲区*/ gtk_text_buffer_insert(GTK_TEXT_BUFFER(show_buffer),&end,text,strlen(text));/*插入文本到缓冲区*/ gtk_text_buffer_insert(GTK_TEXT_BUFFER(show_buffer),&end,"/n",1);/*插入文本到缓冲区*/ } /* clean the input text */ void clean_send_text() { GtkTextIter start,end; gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(input_buffer),&start,&end);/*获得缓冲区开始和结束位置的Iter*/ gtk_text_buffer_delete(GTK_TEXT_BUFFER(input_buffer),&start,&end);/*插入到缓冲区*/ } /* get the input text,and send it */ void send_text() { GtkTextIter start,end; gchar *text; if(issucceed==-1){ /* Haven't create a socket */ show_err("Not connected.../n"); } else { /* Socket creating has succeed ,so send message */ text=(gchar *)malloc(MAXSIZE); if(text==NULL) { printf("Malloc error!/n"); exit(1); } /* get text */ gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(input_buffer),&start,&end); text=gtk_text_buffer_get_text(GTK_TEXT_BUFFER(input_buffer),&start,&end,FALSE); /* If there is no input,do nothing but return */ if(strcmp(text,"")!=0) { send_func(text); clean_send_text(); show_local_text(text); } else show_err("The message can not be empty.../n"); free(text); } } /* show errors such as "no input","haven't create sockt" etc. */ void show_err(char *err) { GtkTextIter start,end; gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(show_buffer),&start,&end);/*获得缓冲区开始和结束位置的Iter*/ gtk_text_buffer_insert(GTK_TEXT_BUFFER(show_buffer),&end,err,strlen(err)); } /* get IP address and create socket */ void get_ip(GtkWidget *button,gpointer ip_text) { gchar *serv_ip; int res; serv_ip=(gchar *)gtk_entry_get_text(GTK_ENTRY((GtkWidget *)ip_text)); res=build_socket(serv_ip); if(res==1) show_err("IP Address is Invalid.../n"); else if(res==-1) show_err("Connect Failure... /n");/*插入文本到缓冲区*/ else{ show_err("Connect Successful... /n"); issucceed=0; } } /* show the received message */ void show_remote_text(char rcvd_mess[]) { GtkTextIter start,end; gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(show_buffer),&start,&end);/*获得缓冲区开始和结束位置的Iter*/ gtk_text_buffer_insert(GTK_TEXT_BUFFER(show_buffer),&end,"Server:/n",8);/*插入文本到缓冲区*/ gtk_text_buffer_insert(GTK_TEXT_BUFFER(show_buffer),&end,rcvd_mess,strlen(rcvd_mess));/*插入文本到缓冲区*/ gtk_text_buffer_insert(GTK_TEXT_BUFFER(show_buffer),&end,"/n",1);/*插入换行到缓冲区*/ } /* quit */ void quit_win(GtkWidget *window,gpointer data) { gtk_main_quit(); }
makefile代码
OBJ=client.o cl_sock.o
OBJ1=server.o se_sock.o
server:server.o se_sock.o server.h
gcc -Wall $(OBJ1) -o server `pkg-config gtk+-2.0 --libs` -l pthread
server.o:server.c server.h
gcc -Wall -c $< `pkg-config gtk+-2.0 --cflags`
server_sock.o:se_sock.c server.h
gcc -Wall -c $<
client:client.o cl_sock.o client.h
gcc -Wall $(OBJ) -o client `pkg-config gtk+-2.0 --libs` -l pthread
client.o:client.c client.h
gcc -Wall -c $< `pkg-config gtk+-2.0 --cflags`
client_sock.o:cl_sock.c client.h
gcc -Wall -c $<
clean:
rm *.o