Linux系统下TFTP 和QT下聊天程序设计.docx
《Linux系统下TFTP 和QT下聊天程序设计.docx》由会员分享,可在线阅读,更多相关《Linux系统下TFTP 和QT下聊天程序设计.docx(19页珍藏版)》请在冰豆网上搜索。
Linux系统下TFTP和QT下聊天程序设计
安徽工业大学
嵌入式系统及应用综合实验报告
Linux系统下TFTP和QT下聊天程序设计
姓名:
学号:
专业:
年级:
指导教师:
2011年6月日
课前资料:
●参考资料查阅工具:
man,如manls,manmake;
●C编写手册,机器上“linuxc参考”;
●Shell编写手册,机器上“linuxshell参考“;
●Makefile编写手册,机器上“makefile参考“;
●Awk编写手册,机器上“awk参考“;
●经典书籍,学习linux,unix的最佳书籍“Linux,unixshell编程指南“
一、实验题目:
熟悉linux操作系统下最简单实用的通信程序socket.最好能全部完成,否则按照完成情况打分。
二、实验目的:
通过对socket的编写,可以了解linux下最简单实用的进程通信方法,为后续信号灯、消息队列等学习奠定基础。
三、实验设备及环境:
1.硬件设备:
PC机一台
2.软件环境:
安装Linux操作系统,并安装相关的程序开发环境,如C\C++\tsh\bsh等编程语言环境。
四、实验内容及要求:
(1)用C语言编程实现linux简单的聊天室功能。
⏹用户程序命名为client.c;服务器程序命名为server.c
⏹绑定端口等信息见实验方法内容;
⏹要求client可以通过socket连接server
◆在client,提示输入服务器ip
◆若连接server的socket建立成功,返回提示信息
◆Client输入的聊天内容在client端(多个client端)和server端同时显示;
◆多个client可同时接入server,进入聊天室,最多支持20个client;
◆Client端输入quit退出连接,server端提示client退出。
◆可选择使用多线程实现多客户端;
◆其他细节见输出结果;
五、实验方法内容
1.需要的头文件
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
2.主要的常量变量
客户端:
#defineTRUE1
#definePORT5000
intquit=0;//quit表示是否用户确定退出
服务器端:
#defineMAXLINE1000//在一条消息中最大的输出字符数
#defineLISTENQ20//最大监听队列
#definePORT5000//监听端口
#defineMAXFD20//最大的在线用户数量
void*get_client(void*);
inti,maxi=-1;//maxi表示当前client数组中最大的用户的i值
intclient[MAXFD];
3.主要模块
客户端:
intmain(void)
void*get_server(void*sockfd)
//get_server函数,用于接受服务器转发的消息
服务器端:
intmain()
void*get_client(void*sockfd)//运行get_client函数,处理用户请求
六.代码
考虑大家没做过,给几个例子:
参考socket编程.pdf
/*******客户端程序client.c************/
#include
#include
#include
#include
#include
#include
#include
#include
#defineTRUE1
#definePORT5000
staticintsockfd;
voidrecvfromserver()//接受服务器消息线程入口函数
{
charmes[1024];
intnbytes=0;
while
(1)
{
memset(mes,0,sizeof(mes));
nbytes=read(sockfd,mes,sizeof(mes));
if(nbytes>0)
{
mes[nbytes]='\0';
printf("%s\n",mes);
}
}
pthread_exit(NULL);
}
intmain(intargc,char*argv[])
{
//intsockfd;
charbuffer[1024];
structsockaddr_inserver_addr;
structhostent*host;
intportnumber,nbytes;
charstrhost[16];
charclientname[20];
charmes[1024];
intthr_id;/*threadIDforthenewlycreatedthread*/
pthread_tp_thread;/*thread'sstructure*/
if(argc!
=1)
{
fprintf(stderr,"Usage:
%s\a\n",argv[0]);
exit
(1);
}
printf("请输入服务器ip地址\n");
scanf("%s",strhost);
if((host=gethostbyname(strhost))==NULL)
{
fprintf(stderr,"Gethostnameerror\n");
exit
(1);
}
/*客户程序开始建立sockfd描述符*/
printf("正在建立套接口...\n");
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
{
fprintf(stderr,"SocketError:
%s\a\n",strerror(errno));
exit
(1);
}
/*客户程序填充服务端的资料*/
bzero(&server_addr,sizeof(server_addr));
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(PORT);
server_addr.sin_addr=*((structin_addr*)host->h_addr);
printf("套接口创建成功,正在链接服务器...\n");
/*客户程序发起连接请求*/
if(connect(sockfd,(structsockaddr*)(&server_addr),sizeof(structsockaddr))==-1)
{
fprintf(stderr,"ConnectError:
%s\a\n",strerror(errno));
exit
(1);
}
/*连接成功了*/
printf("链接服务器成功\n欢迎来到聊天室\n");
printf("请输入你的用户昵称\n");
scanf("%s",clientname);
//write(sockfd,clientname,sizeof(clientname));
printf("\n\n开始聊天吧(\"Quit\"断开连接)\n\n");
thr_id=pthread_create(&p_thread,NULL,recvfromserver,NULL);
while
(1)
{
memset(buffer,0,sizeof(buffer));
memset(mes,0,sizeof(mes));
scanf("%s",buffer);
strcat(mes,clientname);
strcat(mes,":
");
strcat(mes,buffer);
//printf("mainthread%s\n",mes);
if((write(sockfd,mes,sizeof(mes)))==-1)
{
fprintf(stderr,"WriteError:
%s\n",strerror(errno));
exit
(1);
}
if(strcmp(buffer,"Quit")==0)
{
break;
}
}
/*结束通讯*/
close(sockfd);
exit(0);
}
/*******服务器程序(server.c)************/
#include
#include
#include
#include
#include
#include
#include
#include
#defineMAXLINE1000//在一条消息中最大的输出字符数
#defineLISTENQ20//最大监听队列
#definePORT5000//监听端口
#defineMAXFD20//最大的在线用户数量
void*get_client(void*);
intsockfd,i;
staticintmaxi=0;//maxi表示当前client数组中最大的用户的i值
staticintclient[MAXFD];
voidrecvandsend(void)//监听转发线程入口函数
{
intindex=0;
intnbytes=0;
charbuffer[1024];
intlen;
intoutindex=0;
while
(1)
{
if(maxi>0)
{
memset(buffer,0,sizeof(buffer));
nbytes=0;
//index++;
nbytes=read(client[index++],buffer,sizeof(buffer));
//printf("%d,%d\n",index,client[index]);
if(nbytes>0)
{
buffer[nbytes]='\0';
printf("%s\n",buffer);
outindex=0;
while(outindexif(write(client[outindex++],buffer,sizeof(buffer))==-1)
{
fprintf(stderr,"WriteError:
%s\n",strerror(errno));
exit
(1);
}
}
}
if(index>=maxi)
index=0;
}
pthread_exit(NULL);
}
intmain(intargc,char*argv[])
{
//intclient_fd[LISTENQ],clientnum=0;;
structsockaddr_inserver_addr;
structsockaddr_inclient_addr;
intsin_size,portnumber;
charhello[]="Hello!
AreYouFine?
\n";
intthr_id;/*threadIDforthenewlycreatedthread*/
pthread_tp_thread;/*thread'sstructure*/
intnew_fd=0;
memset(client,0,sizeof(client));
if(argc!
=1)
{
fprintf(stderr,"Usage:
%sportnumber\a\n",argv[0]);
exit
(1);
}
/*服务器端开始建立socket描述符*/
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
{
fprintf(stderr,"Socketerror:
%s\n\a",strerror(errno));
exit
(1);
}
/*服务器端填充sockaddr结构*/
bzero(&server_addr,sizeof(structsockaddr_in));
server_addr.sin_family=AF_INET;
server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
server_addr.sin_port=htons(PORT);
/*捆绑sockfd描述符*/
if(bind(sockfd,(structsockaddr*)(&server_addr),sizeof(structsockaddr))==-1)
{
fprintf(stderr,"Binderror:
%s\n\a",strerror(errno));
exit
(1);
}
printf("服务器监听端口%d...\n",PORT);
/*监听sockfd描述符*/
if(listen(sockfd,LISTENQ)==-1)
{
fprintf(stderr,"Listenerror:
%s\n\a",strerror(errno));
exit
(1);
}
thr_id=pthread_create(&p_thread,NULL,recvandsend,NULL);
printf("欢迎来到本聊天室\n");
while
(1)
{
/*服务器阻塞,直到客户程序建立连接*/
if(maxi>=20)
{
printf("以达到人数上线\n");
continue;
}
sin_size=sizeof(structsockaddr_in);
if((new_fd=accept(sockfd,(structsockaddr*)(&client_addr),&sin_size))==-1)
{
fprintf(stderr,"Accepterror:
%s\n\a",strerror(errno));
exit
(1);
}
/*fprintf(stderr,"Servergetconnectionfrom%s\n",inet_ntoa(client_addr.sin_addr));*/
client[maxi++]=new_fd;
printf("\n新用户进入聊天室%d\n",new_fd);
}
close(sockfd);
exit(0);
}
七、实验结果
1.执行结果
●服务器打开
●客户端打开,并输入了地址,昵称
●服务器端显示
●客户端2进入
●服务器显示
●张三输入
●李四端显示
●服务器显示
●李四输入
●张三显示
●服务器显示
2.结果分析
这是一个聊天室程序,可以实现群聊的功能,即当某个客户发出消息后,服务器和其他个客户端都能收到此消息。
且能够显示客户端的用户名。
但客户端退出聊天室后,服务器和其他在线客户端会有提示。
实现群聊的机制是:
当某个客户端需要发送消息是,它将此消息发送给服务器,服务器再将此消息转发给各客户端,各客户端之间是无连接的,即相互之间不能直接通信。
因此,在服务器中,有两个线程,主线程用来监听是否有客户端登录服务器,若有,建立与其连接的套接字,并存入在线客户序列里,辅助线程是接收转发线程,其依次读取个客户端,看是否有消息送达,若有,取出,并转发给各其他客户端。
在客户端也有两个线程,主线程用来向服务器发送消息,辅助线程用来接收服务器发出的消息。
存在的问题是:
1.当有用户下线是,虽会在服务器和各客户端提示用户下线,但是并未删除其在服务器中的套接字,致使后来用户不能进入。
2.服务器的辅助线程对各客户端采取轮流监听的策略,但是因为使用read()函数会阻塞线程,致使出现各客户端必须按登陆顺序依次发言的尴尬情况。
经过查找,可以使用select()函数跨过阻塞,正在试验中。
八、实验总结
通过这次实验,熟悉了linux下的socket网络编程的基本步骤,和一些基本函数调用,并对多线程有了了解,但对线程的调度还是很模糊,需要深入学习和多加练习。
教师评价
评定项目
A
B
C
D
评定项目
A
B
C
D
算法正确
界面美观,布局合理
程序结构合理
操作熟练
语法、语义正确
解析完整
实验结果正确
文字流畅
报告规范
题解正确
其他:
评价教师签名:
年月日