设计聊天室实验报告.docx
《设计聊天室实验报告.docx》由会员分享,可在线阅读,更多相关《设计聊天室实验报告.docx(15页珍藏版)》请在冰点文库上搜索。
设计聊天室实验报告
设计性实验项目简介
实验课程名称
TCP/IP协议分析
实验项目名称
聊天室
实验项目性质
1、综合性2、设计性√
主讲教师
开课年级
开课专业
实验地点
开课日期
开课时间
实验项目简介:
实验目的
(1)通过编写聊天室的功能理解socket模型下客户端和服务器的编写
(2)通过自己增加私聊的功能练习网络编程的方式
(3)掌握Linux平台网络数据的传送方法。
实验容
(1)编写聊天室的客户端和服务器端,客户端主要功能是发送信息,服务器端的主要功能是将客户端发的容转发到除发送端以外的所有客户端,实现客户端和客户端的通信。
(2)编写基于原始套接字的网络通信原型系统;
实验条件
学院提供网络实验室,1台/学生微型计算机,安装有Linux虚拟机。
实验原理
实验中,客户应用程序向服务器程序请求服务。
服务进程一直处于休眠状态,直到一个客户向这个服务的地址提出了连接请求。
在这个时刻,服务程序被"惊醒"并且为客户提供服务-对客户的请求作出适当的反应。
服务器部分:
1.首先判断客户端的用户是不是第一个登陆,对于第一次登陆的用户后面加上“/”,首先判断user_link是否为有位置,有的话并把username写入,usercount设置为1,并转发出xxjointheroom。
2.对于登陆过的用户可惜相互通讯,客户端写入信息发给服务器端,服务器端转发出去。
3.对于输出用户功能,客户端输入“list”,服务器通过比较给客户端传输全部的用户。
4.对于私聊功能,通过“*”符号进行判断,利用指针取出“*”之后的名字,只对该名字进行转发。
servse.c服务器端代码
#include
#include
#include
#include
#include
#include"chat.h"
intinit_ser(int);
voidset_name(char*line,char*name)
{
strcpy(name,&line[1]);
sprintf(line,"%sjointheroom\n",name);
}
voidadd_name(char*line,char*name)
{
chartheline[MAX_LINE];
strcpy(theline,name);
strcat(theline,":
");
strcat(theline,line);
strcpy(line,theline);
}
intuser_free(intuser_link[MAX_CLIENT])
{
inti=0;
while((user_link[i]!
=0)&&(iif(i==MAX_CLIENT)return(-1);
return(i);
}
intmain(void)
{
intsockfd;
intnew_sockfd;
intuser_link[MAX_CLIENT];
intuserfd[MAX_CLIENT];
charusername[MAX_CLIENT][MAX_NAME];
charline[MAX_LINE];
intuserCount;
unsignedintcli_len;
structsockaddr_incli_addr;
FILE*file;
intport,i,j,k,l;
intlength;
charname[MAX_LINE];
charcmpstr[MAX_LINE];
charlinestr[MAX_LINE];
char*ps,*pt,*pr;
char*pl,*pn;
file=fopen("config","r");
fgets(line,MAX_LINE,file);
fscanf(file,"%d",&port);
fclose(file);
printf("%d\n",port);
sockfd=init_ser(port);
if(sockfd==0)
{
printf("Initseversocketerror\n");
fflush(stdout);
//exit
(1);
}//Socketinitdone
listen(sockfd,MAX_CLIENT);
cli_len=sizeof(cli_addr);
for(i=0;i{
user_link[i]=0;
username[i][0]='\0';
}
userCount=0;
fcntl(sockfd,F_SETFL,O_NONBLOCK);
for(;;){
if((userCount=user_free(user_link))>=0)
{
new_sockfd=accept(sockfd,(structsockaddr*)&cli_addr,&cli_len);
fcntl(new_sockfd,F_SETFL,O_NONBLOCK);
if(new_sockfd<0)
{
user_link[userCount]=0;
}
else
{
user_link[userCount]=1;
userfd[userCount]=new_sockfd;
}
}//ifuserCount>=0
for(i=0;iif(user_link[i]==1){
length=read(userfd[i],line,MAX_LINE);
if(length==0)//socketisclosed.
{
user_link[i]=0;
username[i][0]='\0';
}
elseif(length>0){
line[length]='\0';
if((line[0]=='/')&&(username[i][0]=='\0'))
{
set_name(line,username[i]);
for(j=0;j{
if((j!
=i)&&(user_link[j]==1))
{
write(userfd[j],line,strlen(line));
}
}
}
elseif(line[0]=='l'&&line[1]=='i'&&line[2]=='s'&&line[3]=='t')
{
bzero(line,MAX_LINE);
for(k=0;k{
if(user_link[k]==1)
{
strcat(line,username[k]);
strcat(line,"");
}
}
//strcat(line,'\0');
write(userfd[i],line,strlen(line));
}
elseif(line[0]=='*')
{
ps=cmpstr;
pt=line;
pr=linestr;
pt++;
while((*pt)!
=':
')
{
*ps=*pt;
ps++;
pt++;
}
*ps='\0';
pt++;
while((*pt)!
='\0')
{
*pr=*pt;
pr++;
pt++;
}
*pr='\0';
for(l=0;l{
if(strcmp(cmpstr,username[l])==0)
{
add_name(linestr,username[i]);
write(userfd[l],linestr,strlen(linestr));
}
}
}
else{
add_name(line,username[i]);
for(j=0;j{
if((j!
=i)&&(user_link[j]==1))
{
write(userfd[j],line,strlen(line));
}
}
}
}//length>0
}//user_link[i]==1
}//for
}//for
return0;
}
intinit_ser(intport)
//Ifsuccess,returnsockfd,elsereturn0
{
intSERV_TCP_PORT;
intsockfd;
structsockaddr_inserv_addr;
SERV_TCP_PORT=port;
if((sockfd=socket(AF_INET,SOCK_STREAM,0))<0){
perror("socket:
");
printf("server:
can`topenstreamsocker.\n");
fflush(stdout);
return(0);
}
bzero((char*)&serv_addr,sizeof(serv_addr));
serv_addr.sin_family=AF_INET;
serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
serv_addr.sin_port=htons(SERV_TCP_PORT);
if(bind(sockfd,(structsockaddr*)&serv_addr,
sizeof(serv_addr))<0){
perror("bind:
");
printf("server:
can`tbindlocaladdress\n");
fflush(stdout);
return(0);
}
return(sockfd);//successful.
}
客户端部分:
1.手动输入服务器端IP地址和端口号进行连接
2.发送消息给服务器端并显示服务器端回传的消息
3.监控连接状态,客户离开或故障时从列表中删除相应表项,并及时更新连接表
client.c客户端代码:
#include
#include
#include
#include
#include
#include
#include
#include
#defineMAX_LINE500
#defineMAX_NAME100
intinit_cli();
#ifndef__SELECT__
intmain(void)
{
intsockfd;
intstatus;
charstr[MAX_LINE];
charname[MAX_NAME];
sockfd=init_cli();
if(sockfd==0){
printf("Initclientsocketerror.\n");
fflush(stdout);
exit
(1);
}
fcntl(sockfd,F_SETFL,O_NONBLOCK);
fprintf(stdout,"Pleaseinputyourname:
");
fscanf(stdin,"%s",name);
strcpy(str,"/");
strcat(str,name);
write(sockfd,str,strlen(str));
fcntl(0,F_SETFL,O_NONBLOCK);
while
(1){
if((status=read(sockfd,str,MAX_LINE))>=0)
{
if(status==0)exit(0);
str[status]='\0';
printf("%s",str);
fflush(stdout);
}
if((status=read(0,str,MAX_LINE))>0)
{
str[status]='\0';
if(str[0]=='q')
{
sprintf(str,"Ileavetheroom.\n");
write(sockfd,str,strlen(str));
close(sockfd);
exit(0);
}
write(sockfd,str,strlen(str));
}
}
return1;
}
#endif//__SELECT__
intinit_cli(void)
//Returnsockfdifsuccessful,else0
{
intsockfd;
intSERV_TCP_PORT;
charSERV_HOST_ADDR[MAX_LINE];
FILE*fd;
structsockaddr_inserv_addr;
fd=fopen("config","r");
fgets(SERV_HOST_ADDR,MAX_LINE,fd);
fscanf(fd,"%d",&SERV_TCP_PORT);
fclose(fd);
bzero((char*)&serv_addr,sizeof(serv_addr));
serv_addr.sin_family=AF_INET;
serv_addr.sin_addr.s_addr=inet_addr(SERV_HOST_ADDR);
serv_addr.sin_port=htons(SERV_TCP_PORT);
if((sockfd=socket(AF_INET,SOCK_STREAM,0))<0){
printf("client:
can`topenstreamsocker.\n");
fflush(stdout);
return(0);
}
if(connect(sockfd,(structsockaddr*)&serv_addr,
sizeof(serv_addr))<0){
printf("client:
can`tconnecttoserver\n");
fflush(stdout);
return(0);
}
return(sockfd);
}
运行结果:
服务器端运行结果,显示端口号并处于等待连接状态:
群聊功能,四个客户端代表四个用户,通过服务器的转发实现通信。
显示所有的用户功能,通过发送“list”由客户端发送所有的用户名字。
私聊功能,通过“*”符号作为标识符实现两个用户之间的私有通信。
实验感悟
本实验的私聊功能较为难实现,在老师和同学的帮助下经过一次次的验证和修改最终实现了该功能,最终本实验可以群聊也可以私聊。
本实验利用的是C语言编程,需要C语言和linux网络编程基础,尤其对socket编程和C语言数组和指针的应用,锻炼了我们对两者的编程能力,在修改代码的过程中加深了我们对编程的理解。
注:
开课时间填本实验项目所有实验班的具体上课时间,如11月12日下午3:
00-5:
00。