Windows-C语言构建网络聊天室

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

第1页共13页WindowsC语言构建网络聊天室利用C语言编写Windows应用程序有两种方式:一种是WindowsC编程方式,另一种是VisualC++编程方式。在一般情况下,VisualC++编程方式编写的程序源代码量小、开发时的工作量小、工作难度也较小,但编译后的代码量较大,运行速度略低;而WindowsC编程方式编写的程序源代码量虽然较大,但可执行代码效率高。随着技术的进步,VisualC++编程方式已被广泛采用,但象网络编程等一些对速度要求高、对硬件操作较多的程序,大多数还是用WindowsC编程方式开发的。另外,学习WindowsC程序设计,还有助于更深入地了解Windows的内幕和WindowsAPI。基本的网络编程都是建立在Winsock基础上的。Winsock是90年代初,为了方便网络编程,由Microsoft联合了其他几家公司共同制定的一套WINDOWS下的网络编程接口,它是通过C语言的动态链接库方式提供给用户及软件开发者的,主要由winsock.h头文件和动态链接库winsock.dll组成,目前有两个版本:Winsock1.1和Winsock2.0。作为网络编程接口,Winsock屏蔽了网络底层的复杂的协议和数据结构,使得编程人员对网络的操作变得非常简单,因此,在Win32平台上,访问众多的基层网络协议,Winsock是首选接口。用Winsock构建一个网络聊天室,有两种基本的方式:数据报方式和流方式。一、面向无连接的数据报方式数据报方式又称无连接方式,对应的是UDP(UserDatagramProtocol)协议。这种方式不提供数据无错保证,数据可能丢失或重复并且接收顺序混乱,后发出的报文可能会先收到,并且报文的长度是有限制的;不过,由于取消了重发校验机制,能够达到较高的通信速率,可以用于对数据可靠性要求不高的通信,如实时的语音、图像传送和广播消息等。和C语言一样,函数是WindowsC编程的最基本的单位。不过,WindowsC主要使用API函数,而网络编程则主要使用Winsock提供的API函数。数据方式构建网络聊天室主要使用了以下几个函数:1.WSAStartup():初始化。【函数原型】intPASCALFARWSAStartup(WORDwVersionRequired,LPWSADATAlpWSAData);【使用说明】每一个使用winsock的应用程序,都必须进行WSAStart函数调用,并且只有在调用成功之后才能使用其它的winsock网络操作函数。返回值:调用成功返回0;否则,返回出错信息。WversionRequired输入:表示欲使用的Winsock版本,这是一个WORD类型的整数,它的高位字节定义的是次版本号,低位字节定义的是主版本号。LpWSAData输出:是一个指向WSADATA资料的指针。这个资料我们一般不使用。2.Socket():创建一个Socket。【函数原型】SOCKETsocket(intaf,inttype,intproctocol);【使用说明】Winsock网络通信的第一步通常就是调用这个函数。所有的通信在建立之前都有要创建一个Socket。该函数的功能与文件操作中的fopen()类似,返回值是由Winsock定义的一种数据类型SOCKET,它实际是一个整型数据,是Socket创建成功时,Windows分配给程序的Socket编号,后面调用传输函数时,可以把它像文件指针样引用。如果Socket建立失败,返回值WIVALID_SOCKET。Af输入:指addressfamily(地址族),一般都填AF_INET,表示是在Internet上的Socket;Type输入::是Socket的类型,当采用流连接方式时,用SOCK_STREAM;采用数据报文方式时,用SOCK_DGRAM。第2页共13页Proctocol输入:一般都有为0,表示对两种类型的Socket分别采用缺省的TCP和UDP传输协议。3.Bind():为创建Socket指定通信对象。【函数原型】intbind(SOCKETs,conststructsockaddrFAR*name,intnamelen);【使用说明】成功创建了Socket之后,就应该选定通信的对象。首先是自己的程序要与网上的哪台计算机通话;其次,在多任务的系统下,该台计算机上可能会有几个程序在工作,必须指出要与哪个程序通信。前者可以通过IP地址来确定,而后者则由端口号来确定的。一台计算机有65536个端口,端口号范围为0~65535,不同的通信程序使用不同的端口。不过,1024以下的端口号一般都已被一些常用的网络服务程序所占用,因此,编制自己的通信程序时,指定的端口号应大于1024。s输入:上一步创建Socket时创建好的套接字。name输入:是指向描述通信对象地址信息的结构体strictsockaddr_in的指针。namelen输入:name结构体的长度。Sockaddr_in的定义如下:structsockaddr_in{shortsin_family;unsignedshortsin_port;structin_addrsin_addr;charsin_zero[8];};其中,sin_family是指一套地址族,它指定所要使用的通信协议,通常设为AF_INET;sin_port端口号;sin_addr是IP地址;而sin_zero[8]的作用,只是使该结构的大小和SOCKADDR结构大小相同。IP地址sin_addr结构定义如下:structin_addr{union{struct{u_chars_b1,s_b2,s_b3,s_b4;}S_un_b;struct{u_shorts_w1,s_w2;}S_un_w;u_longS_addr;}S_un;};这样,对于一个IP地址,例如“192.168.0.1”,你可以用以下三种方法赋给一个sockaddr结构体(例如structsockaddr_inm_addr;):方法1:m_addr.sin_addr.S_un.S_un_b.s_b1=192;m_addr.sin_addr.S_un.S_un_b.s_b2=168;m_addr.sin_addr.S_un.S_un_b.s_b3=0;m_addr.sin_addr.S_un.S_un_b.s_b4=1;方法2:m_addr.sin_addr.S_un.S_un_w.s_w1=(1688)|192;m_addr.sin_addr.S_un.S_un_w.s_w2=(18)|0;方法3:m_addr.sin_addr.S_un.S_addr=(124)|(016)|(1688)|192;为了更方便地赋值,winsock还为我们提供了一个函数inet_addr(),可以把用字符串表示的IP地址“192.168.0.1”直接赋给结构体m_addr:char*IP_String=”192.168.0.1”;m_addr.sin_addr.S_un.S_addr=inet_addr(IP_String);第3页共13页4.recvfrom()/sendto():【函数原型】intrecvfrom(SOCKETs,charFAR*buf,intlen,intflags,structsockaddrFAR*from,intFAR*fromlen);intsendto(SOCKETs,constcharFAR*buf,intlen,intflags,conststructsockaddrFAR*to,inttolen);【使用说明】s输入:是连接用的socket。buf、len输入:发送或接收的数据包字符串的地址和长度。flags输入:一般取0。from、fromlen/to、tolen输入:含义和用法与bind()中的相同,分别表示接收和发送数据的对象。5.Closesocket():【函数原型】intclosesocket(SOCKETs);【使用说明】和关闭文件操作一样,socketd在使用以后,也要关闭。Internet上的聊天室程序一般都是Client/Server结构的,由服务器提供服务端连接响应,使用者通过客户端程序登录到服务器(面向接连的流方式),或直接向服务端发送报文(面向无连接的数据报方式)。相应地,聊天室程序也就分为服务器端和客户端两部分。面向无连接的数据报方式的程序流程图如图1所示:图1面向无连接的数据报方式流程图可以为服务器端和客户端分别建立如图1、图2所示对话框:调用socket()创建一个监听Socket调用bind()监听socket指定通讯对象调用recvfrom()和sendto()进行通讯调用closesocket()关闭socket调用WSAStartup()初化Winsock调用WSAStartup()初化Winsock调用closesocket()关闭socket调用recvfrom()和sendto()进行通讯调用socket()创建一个会话Socket服务器端客户端第4页共13页图1服务器端图2客户端相应的源程序见附件中的源程序Chat_Room1。二、面向连接的流方式流方式又称无连接方式,对应的是TCP(TransportControlProtocol))协议。在这种方式下,两个通信的应用程序之间先要建立一种连接链路,确定了这条链路之后,数据才能被正确接收和发送。流方式的特点是通信可靠,对数据有校验和重发的机制,通常用来做数据文件的传输如FTP、Telnet等。这种方式主要使用了以下几个函数:1.Connect():【函数原型】intconnect(SOCKETs,conststructsockaddrFAR*name,intnamelen);【使用说明】与通信对象建立连接,主要用在客户端。其中s、name和namelen的含义与使用方法和bind()相同。如果连接失败,该函数会返回SOCKET_ERROR。2.listen():【函数原型】intlisten(SOCKETs,intbacklog);【使用说明】对于服务器端程序,当申请到Socket,并指定通信对象为INADDR_ANY之后,就应该等待一个客户端程序的连接。当没有连接请求时,就进入等待状态,直至有一个请求到达为止。其中:s输入:是socket()创建的socket。backlog输入:等待连接的队列长度,可取1~5。如果当某个客户程序要求连接之时,服务器已与其他客户程序连接,则后来的连接请求会被放在队列中,等待服务器空闲的时候再与之连接。当队列达到指定长度(backlog的值)时,再来的连接请求都将被拒绝。3.accept():【函数原型】SOCKETaccept(SOCKETs,structsockaddrFAR*addr,intFAR*addrlen);【使用说明】对与服务器端程序,在接收到一个连接请求之后,要为这个连接建立一个新的socket,这个任务由accept()函数来完成,并把它作为返回值。新建的Socket与原来的Socket有相同的特性,包括端口号。原来的Socket用于继续等待其他的连接请求,而新生成的Socket才是与客户端进行通信的实际Socket。一般将参数中的SOCKET称做“监听”Socket,它只负责接受连接,不负责通话;而accept返回的SOCKET则称为“会话”Socket,它只负责与客户端通话。参数中的指针addr和addrlen用来返回客户机的sockaddr_in结构体,通过addr可得到客户机的IP地址和连接端口。使用方法则与bind()中的name和namelen相同。4.recv()/send():【函数原型】建立连接后,用来接收和发送数据。其中:第5页共13页s输入:是连接用的socket。buf、len和flags的含义与作用方法与recvfrom()/connect()中

1 / 13
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功