tcp网络聊天系统
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
福州大学物理与信息工程学院专业设计报告
课程:嵌入式系统应用开发
题目:网络聊天系统
姓名:曾聪杰
学号:111300203
年级专业:2013级
指导教师:张志晓
2016年6月16日
目录
一、功能需求 (1)
二、预备知识 (1)
三、总体设计分析 (1)
四、功能模块设计 (3)
五、项目总结 (6)
六、附录 (6)
网络聊天系统
一、功能需求
主从机间互相通信。客户端向服务器发送消息,服务器可以接收来自多个客户端的消息,服务器发送消息,所有客户端都能接收到来自服务器的消息。
二、预备知识
1、文件操作
2、父子进程
3、多线程
4、网络通信、TCP/UDP等
三、总体设计分析
网络通信的总体流程如下图所示:
1、本实验采用AF_INET套接字类型的socket编程进行通信。AF_INET(又称PF_INET)是IPv4 网络协议的套接字类型,选择AF_INET 的目的就是使用IPv4 进行通信。因为IPv4 使用32 位地址,相比IPv6 的128 位来说,计算更快,便于用于局域网通信。
2、本实验为了能实现多客户端通信,采用了多线程方式,接收来自
各个客户端的信息。
四、功能模块设计
1、服务端通信
(1)使用socket()创建TCP套接字(socket)
(2)将创建的套接字绑定到一个本地地址和端口上(Bind)
(3)将套接字设为监听模式,准备接收客户端请求(listen)
(4)采用多线程机制加循坏,可以实现客户端连续发消息以及多个客户端发消息,服务端连续接收消息,并能识别各个客户端。
(5)等待客户请求到来: 当请求到来后,接受连接请求,返回一个对应于此次连接的新的套接字(accept)
(6)用accept返回的套接字和客户端进行通信(使用write()/send()或send()/recv() ),并在标准输入输出设备上显示
(7)返回,等待另一个客户请求
(8)关闭套接字
服务端运行流程:
打开一个终端,运行服务端程序,等待接收来自各个客户端的消息,在接收到各个客户端的消息后,发送消息“I have received your message”到各个客户端:
2、客户端通信
(1)创建套接字(socket)
(2)使用connect()建立到达服务器的连接(connect)
(3)客户端进行通信(使用write()/send()或send()/recv()),并在标准输入输出设备上显示
(4)使用close()关闭客户连接
客户端通信流程:
打开另一个终端,运行客户端1,ip地址为192.168.176.100,向服务端发送消息“i am the first client”
打开另一个终端,运行客户端2,ip地址为192.168.176.101,向服务端发送消息“i am the second client”
打开另一个终端,运行客户端3,ip地址为192.168.176.105,向服务端发送消息“i am the third client”
在以上各个客户端可以看到服务器发来的消息:“I have received your message”。
五、项目总结
1、在服务器与客户端通信出现,收发消息不能随机来,而只能按照服务器发送,客户端接收这样的顺序,实验后验证发现,两个程序在收发的代码里需要格式一致。
2、在终端运行时,总是需要输入客户端和服务端的ip地址,因此为了方便操作,可以通过创建buf将ip地址直接存入这个buf中即可,这样会比较简洁。
3、服务器端在接收到有限个消息之后,会出现错误,这是由于监听队列的数目过少,消息数目超过监听队列大小,导致阻塞的发生。
4、本实验只是一次简单点对点、点对多的通信,服务器真正起到的作用应该是将接收到的客户端的消息再分享给每个客户端,这样才能真正实现多人网络聊天的功能。
5、可以采用epoll机制实现多人聊天,通过创建父子进程,子进程用来接收客户端的消息,并发送到父进程,父进程在通过epoll机制向各个客户端发送子进程所接收到的信息。
六、附录
源程序:
1、服务端代码
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAX_THRD 10
#define FD_MAX 10
void threadRec(void *argv);
void threadSend(void *argv);
int main(int argc, char const *argv[])
{
int fdbuf[FD_MAX];
pid_t pid;
pthread_t thrd[MAX_THRD];
int my_fd,new_fd;
int addr_len;
int thrd_count=0;
char buf[4];
struct sockaddr_in my_addr,new_addr;
if(argc != 2){
printf("%s usage:pls input server's ip\n",argv[0]);
return -1;
}
/*创建socket*/
if((my_fd = socket(AF_INET,SOCK_STREAM,0))== -1){
perror("socket");
exit(EXIT_FAILURE);
}
/*填写地址和端口*/
bzero(&my_addr,sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_addr.s_addr = inet_addr(argv[1]);
my_addr.sin_port = htons(8542);
/*将套接字绑定到本地地址和端口*/
bind(my_fd,(__CONST_SOCKADDR_ARG)&my_addr,(socklen_t)sizeof(my_a ddr));
/*监听队列*/