《Linux系统下TFTP聊天程序设计.doc》由会员分享,可在线阅读,更多相关《Linux系统下TFTP聊天程序设计.doc(28页珍藏版)》请在金锄头文库上搜索。
1、安徽工业大学电气信息学院嵌入式系统及应用综合实验报告Linux系统下TFTP 和QT下聊天程序设计姓 名: 学 号: 专 业: 电子信息工程 年 级: 大学三年级 指导教师: 马小陆 2011年 6月 29 日一、课程设计项目介绍1.项目介绍:本次设计是在Linux下实现简单的文件传输。使用网络套接字Socket和多线程在网络中的应用,并基于Linux下的vi编辑器编写和调试服务器端程序和客户端程序,实现了客户端与服务器之间的连接和通信。可以在虚拟机下开辟两个终端窗口分别建立客户端、服务器目录,运行客户端、服务器程序,可实现查看、下载和上传文件等功能。2.设计目的:作为电子信息工程的主干学科,
2、本次课程设计的目的是结合所学知识,完成 Linux系统下下聊天程序设计同时激起对linux系统编程的兴趣。为今后的嵌入式系统开发打下基础。要求掌握Linux 基本指令,通过对socket的编写,进一步熟悉掌握linux下的各种指令,C+程序以及socket下各种函数的了解。二、总体设计1.工作流程图: TCP服务端socket( )bind( ) listen( )TCP客户端accept( ) socket( )阻塞知道有客户端连接建立连接connect( )请求数据 write( )read( ) 处理请求回应数据read( )write( ) 结束连接read( )close( )clo
3、se( ) 2.主要模块客户端:int main(void)void *get_server(void* sockfd)/get_server函数,用于接收服务器转发的消息服务器端:int main()void *get_client(void *sockfd)/运行get_client函数,处理用户请求3实验要求用C语言编程实现linux简单的聊天室功能。n 用户程序命名为client.c;服务器程序命名为 绑定端口等信息见实验方法内容;n 要求client可以通过socket连接serveru 在client端输入./client+ip地址+端口号连接服务器u 若连接server 的soc
4、ket建立成功,返回提示信息u Client输入的聊天内容在client端(多个client端)和server端同时显示;u 多个client可同时接入server,进入聊天室;u Client端输入quit退出连接。u 可选择使用多线程实现多客户端;u 其他细节见输出结果;三、详细设计socket( )1.TCP服务器端流程 bind( )listen( )accept( )send( ) | recv( )close( )工作流程是: (1)首先调用socket函数创建一个套接字 (2)然后调用bind函数将其与本机地址及端口号绑定 (3)然后调用 listen在相应的socket上监听
5、(4)当accpet接收到连接服务请求时,将生成一个新的socket, 这个socket代表了客户端与服务器之间的连接。 (5)读取到客户端的请求后由send函数向客户端发送数据 (6)最后由clese关闭该socketsocket( )2.TCP客户端流程connect( )send( ) | recv( )close( )工作流程是:(1)客户端程序首先通过服务器域名获得服务器的IP地址(2)然后创建一个socket(3)调用connect函数与服务器建立连接(4)连接成功之后接收从服务器发送过来的数据(5)最后关闭socket3.主要的数据结构struct sockaddr这个结构体用来
6、存储套接字地址,或者说它是存储一个套接字信息的struct sockaddrunsigned short sa_family; /* 地址族,AF_xxx */ char sa_data14; /* 14 字节的协议地址 */;sa_family一般为AF_INET,代表Internet(TCP/IP)地址族;sa_data则包含该socket的IP地址和端口号。另外还有一种结构类型: struct sockaddr_in struct sockaddr_in short int sin_family; /* 地址族 */ unsigned short int sin_port; /* 端口号
7、 */ struct in_addr sin_addr; /*IP地址 */ unsigned char sin_zero8; /*填充0与struct sockaddr同样大小 */ ;这个结构更方便使用。sin_zero用来将sockaddr_in结构填充到与struct sockaddr同样的长度,可以用bzero()或memset()函数将其置为零。指向sockaddr_in 的指针和指向sockaddr的指针可以相互转换,这意味着如果一个函数所需参数类型是sockaddr时,可以在函数调用的时候将一个指向 sockaddr_in的指针转换为指向sockaddr的指针;或者相反。 st
8、ruct in_addr struct in_addr unsigned long s_addr; ;如果你声明了一个 ina 作为一个 struct sockaddr_in 的结构,那么ina.sin_addr.s_addr就是一个4字节的IP地址(按网络字节顺序排放)。4.关键代码(1)Socket()函数Socket()函数是用来获得套接字的,可以这样去写 #include #include int main() int sockfd; sockfd = socket(int domain,int type,int protocol); return 0; 在这里domain 一般被设置
9、为 AF_INET, type 参数告诉了内核这个socket是什么类型的, SOCK_STREAM或者 SOCK_DGRAM,最后protocol只需设置为0。套接字创建函数socket()的返回值是一个以后可以使用的套接字描述符。如果发生错误,它返回-1,全局变量error 将被设置为错误代码。(2)Bind()函数使用socket函数创建了一个套接字之后还不可以使用它,需要绑定它,bind()函数可以实现同计算机端口绑定的功能。一般来说,用户可以用来绑定的端口号是1024 - 65535,而0 - 1023号是知名端口,这些端口一般固定分配一些服务,用户无权使用它们。 #include
10、#include #include int main() int sockfd; sockfd = socket(int domain,int type,int protocol); /* 已经创建好的一个套接字*/ /*进入绑定阶段*/ struct sockaddr_in myaddr; myaddr.sin_family = AF_INET; myaddr.sin_port = htons(8000); /*需要绑定的端口号*/ myaddr.sin_addr.s_addr = inet_addr(192.168.2.68);/*本机IP */ bzero(&(myaddr.sin_ze
11、ro),8); bind(sockfd,(struct sockaddr*)&myaddr,sizeof(struct sockaddr); /* 需要在这里对BIND返回值进行判断 */ . . . . return 0;Socket相关的函数一般都有一个返回值,在实际的代码中需要对返回值做一个判断,这样在调试程序时会节省很多时间。上面的代码中依然有的值得注意的地方:myaddr.sin_port myaddr.sin_addr.s_addr是网络字节顺序。bind()可以在程序中自动获取机器的IP。 myaddr.sin_port = 0 ; /* 随即选择一个端口 */ myaddr.s
12、in_addr.s_addr = INADDR_ANY; /* 使用自己的地址 */如上,通过设置myaddr.sin_port 为0,bind()可以知道需要它帮助选择合适的端口。通过设置myaddr.sin_addr.s_addr为 INADDR_ANY,bind()知道要将s_addr填充为运行这个进程的机器的IP。这一切都可以要求bind()来自动完成。其实还有更加严谨的做法。可以保证程序在编译时不会出问题。 myaddr.sin_port = htons(0) ; /* 随即选择一个未用端口 */ myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
13、 /* 使用自己的IP */(3)Listen()函数listen()函数使创建并且绑定的套接字处于一个监听的状态。这个函数很好理解声明如下: #include int listen(int sockfd,int backlog);sockfd 就是用socket()创建出来的socket描述符。backlog 是代表能监听的队列容纳的最大数目。返回值 -1 代表监听失败。(4)Connect()函数如果创建了一个套接字(socket()),绑定了它(bind()),并让它处于监听(listen()),若想去连接它,这时可通过connect()函数实现。有关connect()函数的定义是这样的: