基于套接字的聊天程序设计.docx

上传人:b****6 文档编号:7041750 上传时间:2023-01-16 格式:DOCX 页数:46 大小:231.97KB
下载 相关 举报
基于套接字的聊天程序设计.docx_第1页
第1页 / 共46页
基于套接字的聊天程序设计.docx_第2页
第2页 / 共46页
基于套接字的聊天程序设计.docx_第3页
第3页 / 共46页
基于套接字的聊天程序设计.docx_第4页
第4页 / 共46页
基于套接字的聊天程序设计.docx_第5页
第5页 / 共46页
点击查看更多>>
下载资源
资源描述

基于套接字的聊天程序设计.docx

《基于套接字的聊天程序设计.docx》由会员分享,可在线阅读,更多相关《基于套接字的聊天程序设计.docx(46页珍藏版)》请在冰豆网上搜索。

基于套接字的聊天程序设计.docx

基于套接字的聊天程序设计

 

TCP/IP课程设计

 

题目:

基于套接字的聊天程序设计

 

院系:

计算机与电子信息学院

专业:

网络工程

班级:

网络10-2

学号:

10034120228

姓名:

刘亮

日期:

2012.9.25

 

二O一二年编制

课程设计任务书

 

一、设计题目

基于TCP和UDP套接字的聊天程序设计

二、设计目的:

(1)理解客户机/服务器模型的工作原理;

(2)掌握套接字的概念;

(3)掌握基于套接字的面向连接和无连接客户机/服务器程序的设计原理和相关的WinSockAPI函数;

(4)掌握基于TCP和UDP的程序设计方法。

三、设计内容:

(一)基于TCP的应用编程:

编写一个Client/Server程序对,服务器程序负责接收客户机进程的连接请求,并在服务器进程与客户机进程之间建立通信连接,然后接收客户机进程的传送数据并将其显示在服务器端,同时将欢迎信息发送给客户机进程,通信结束后关闭该客户机进程的连接;客户机进程首先提出对指定服务器的连接请求,建立连接后向服务器进程发送已经建立连接的数据信息,同时接收服务器进程发送过来的数据并显示在客户端。

采用WinSockAIP实现代码。

(二)基于UDP的应用编程:

实现一个基于UDP的客户机/服务器程序,通过设定不同的命令行参数来确定应用进程的不同角色,即充当客户机进程还是服务器进程。

当两个进程运行后,彼此之间可以轮流发送消息,对方接收后显示出来。

四、开发环境和语言:

(1)网络:

局域网;

(2)开发环境:

VS2005以上或VC++6.0以上版本;

(3)开放语言:

C/C++。

 

 

1通信原理分析

1.1TCP协议

TCP协议是一种面向连接的、可靠的传输层协议,为应用层提供可靠、全双工的数据流传输服务,TCP报文封装在IP数据报中。

在使用TCP进行通信时需要首先建立TCP连接后再能进行数据的传输,TCP连接建立为在不安全的IP网络中传输数据提供了数据完整的保障,在通信结束后要将该连接断开。

下面给出基于TCP的c/s通信工作模式:

服务器进程客户端进程

 

1.2UDP协议

UDP是一种无连接、尽最大努力交付的运输层协议,不提供流量控制和确认机制,数据报可能丢失、延迟、乱序到达。

这就是的UDP在实现起来就较为简单,这种简单能很好的应用在实时通信服务中,如实时语音传输、实时视频通信等。

下面给出基于UDP的c/s通信工作模式:

进程A进程B

 

基于udpP的c/s通信模式

1.3套接字的定义

套接字我们可以认为就是通信的一端,其主要包括协议、ip、端口号。

将两个套接字连接在一起就可以实现端到端的网络通信了。

在套接字中封装了网络和传输层协议,从而为程序员屏蔽了底层通信的复杂性。

针对不同通信的需求,在TCP/IP协议中提供了3种不同套接字类型,分别为:

流式套接字(SOCK_STREAM)、数据保式套接字(SOCK_DGRAM)、原始套接字(SOCK_RAW)。

流式套接字(SOCK_STREAM)提供面向连接的,可靠的数据传输服务,数据无差错,无重复的发送,且按发送的顺序接收,基于TCP协议。

数据保式套接字(SOCK_DGRAM)提供无连接的服务,数据包以独立包形式发送,不提供无错误的保证,数据可能丢失或重复,且接收顺序混乱,基于UDP协议。

原始套接字(SOCK_RAW)主要是在编写自定义底层协议的应用程序时使用。

1.4客户机/服务器模式的运行原理

网络应用程序一般是以客户机/服务器的模型的方式工作的。

在这种工作方式中,一个服务器程序通常事先启动,并在一个熟知端口侦听对服务器的请求。

当客户机应用程序需要某种服务时,需向提供这种服务的服务器发出请求,服务器在接收到请求后,向客户机发出相应请求信息。

这样客户机应用程序和服务器程序之间便建立了通信连接,此后可以进行数据通信。

通信任务完成后需要关闭它们之间的通信连接。

2系统设计

2.1基于TCP应用程序设计:

 

2.2基于UDP应用程序设计:

服务器进程

登陆,注册信息到服务器

请求客户A的ip和端口信息

登陆,注册信息到服务器

请求客户B的ip和端口信息

 

客户机B进程

客户机A进程

3详细设计

3.1基于TCP的应用程序设计:

3.1.1服务器设计:

#include

#include

usingnamespacestd;

#include

 

intmain(intargc,char*argv[])

{

constintDEFAULT_PORT=5000;

WORDwVersionRequested;

WSADATAwsaData;

interr,iLen;

wVersionRequested=MAKEWORD(2,2);

err=WSAStartup(wVersionRequested,&wsaData);

if(err!

=0)

{

cout<<"加载WinSock失败!

";

return0;

}

//创建用于监听的套接字

SOCKETsockSrv=socket(AF_INET,SOCK_STREAM,0);//创建服务器监听套接字

if(sockSrv==INVALID_SOCKET)

{

cout<<"socket()fail:

"<

return0;

}

SOCKADDR_INaddrSrv;

charcip[20]="";

intport;

chartype;

cout<<"服务器基本设置为ip:

127.0.0.1端口:

5000"<

cout<<"是否从新设置:

YorN"<

cin>>type;

if(type=='Y')

{

cout<<"IP:

";

cin>>cip;

//ip=cip;

cout<<"端口:

";

cin>>port;

addrSrv.sin_family=AF_INET;

addrSrv.sin_addr.S_un.S_addr=inet_addr(cip);

addrSrv.sin_port=htons(port);

}

else

{

addrSrv.sin_family=AF_INET;

addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");

addrSrv.sin_port=htons(DEFAULT_PORT);

}

//绑定本地主机IP和端口

err=bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));

if(err!

=0)

{

cout<<"bind()fail:

"<

return0;

}

cout<<"Serverhasbeenstartedsuccessfully..."<

//监听

err=listen(sockSrv,5);

if(err!

=0)

{

cout<<"listen()fail:

"<

return0;

}

cout<<"Serverwaiting:

..."<

SOCKADDR_INaddrClient;

intlen=sizeof(SOCKADDR);

while

(1)

{

SOCKETsockConn=accept(sockSrv,(SOCKADDR*)&addrClient,&len);//接收客户进程连接请求

if(sockConn==INVALID_SOCKET)

{

cout<<"accept()fail:

"<

break;

}

charrecvBuf[1024]="\0";

iLen=recv(sockConn,recvBuf,1024,0);//接收数据

if(iLen==SOCKET_ERROR)

{

cout<<"recv()fail:

"<

break;

}

recvBuf[iLen]='\0';

cout<

 

charsendBuf[1024],hostname[100];

if(gethostname(hostname,100)!

=0)//获取主机名称

strcpy(hostname,"None");

sprintf(sendBuf,"welcome%sconnectedto%s!

",inet_ntoa(addrClient.sin_addr),hostname);

err=send(sockConn,sendBuf,strlen(sendBuf)+1,0);//发送数据

if(err==SOCKET_ERROR)

{

cout<<"send()fail:

"<

break;

}

while

(1)

{

charrecvBuf[1024]="\0";

iLen=recv(sockConn,recvBuf,1024,0);//接收数据

if(iLen==SOCKET_ERROR)

{

cout<<"recv()fail:

"<

break;

}

recvBuf[iLen]='\0';

cout<

cout<<"请输入你要发送的消息,输入E退出"<

charsendBuf[1024];

cin>>sendBuf;

stringstr=sendBuf;

if(pare("E"))

{

err=send(sockConn,sendBuf,strlen(sendBuf)+1,0);//发送数据

if(err==SOCKET_ERROR)

{

cout<<"send()fail:

"<

break;

}

}

else

{

break;

}

}

closesocket(sockConn);//关闭套接字

cout<<"Serverwaiting:

..."<

}

WSACleanup();

return0;

}

3.1.2客户端设计:

#include

#include

usingnamespacestd;

#include

intmain(intargc,char*argv[])

{

constintDEFAULT_PORT=5000;

WORDwVersionRequested;

WSADATAwsaData;

interr,iLen;

wVersionRequested=MAKEWORD(2,2);

err=WSAStartup(wVersionRequested,&wsaData);

if(err!

=0)

{

cout<<"加载WinSock失败!

";

return0;

}

//创建用于连接的套接字

SOCKETsockClient=socket(AF_INET,SOCK_STREAM,0);

if(sockClient==INVALID_SOCKET)

{

cout<<"socket()fail:

"<

return0;

}

SOCKADDR_INaddrSrv;

//stringip;

charcip[20]="";

intport;

chartype;

cout<<"服务器基本设置为ip:

127.0.0.1端口:

5000"<

cout<<"是否从新设置:

YorN"<

cin>>type;

if(type=='Y')

{

cout<<"IP:

";

cin>>cip;

//ip=cip;

cout<<"端口:

";

cin>>port;

addrSrv.sin_family=AF_INET;

addrSrv.sin_addr.S_un.S_addr=inet_addr(cip);

addrSrv.sin_port=htons(port);

}

else

{

addrSrv.sin_family=AF_INET;

addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");

addrSrv.sin_port=htons(DEFAULT_PORT);

}

err=connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));//请求连接服务器进程

if(err==INVALID_SOCKET)

{

cout<<"connect()fail:

"<

return0;

}

charsendBuf[1024],hostname[100];

if(gethostname(hostname,100)!

=0)//获取主机名称

strcpy(hostname,"None");

strcpy(sendBuf,hostname);

strcat(sendBuf,"haveconnetedtoyou!

");

err=send(sockClient,sendBuf,strlen(sendBuf)+1,0);//发送数据

if(err==SOCKET_ERROR)

{

cout<<"send()fail:

"<

return0;

}

 

charrecvBuf[1024];

iLen=recv(sockClient,recvBuf,1024,0);//接收数据

if(iLen==0)

return0;

elseif(iLen==SOCKET_ERROR)

{

cout<<"recv()fail:

"<

return0;

}

else

{

recvBuf[iLen]='\0';

cout<

}

while

(1)

{

charsendBuf[1024];

cout<<"请输入你要发送的消息,输入E退出"<

cin>>sendBuf;

stringstr=sendBuf;

if(pare("E"))

{

err=send(sockClient,sendBuf,strlen(sendBuf)+1,0);//发送数据

if(err==SOCKET_ERROR)

{

cout<<"send()fail:

"<

return0;

}

}

else

{

break;

}

 

charrecvBuf[1024];

iLen=recv(sockClient,recvBuf,1024,0);//接收数据

if(iLen==0)

return0;

elseif(iLen==SOCKET_ERROR)

{

cout<<"recv()fail:

"<

return0;

}

else

{

recvBuf[iLen]='\0';

cout<

}

}

 

closesocket(sockClient);//关闭套接字

WSACleanup();

}

 

3.2基于UDP的应用程序设计:

3.2.1服务端设计:

CUDPSocket类,该类主要负责启动套接字,并接受客户发来的数据和发送数据

下面给出该类的源代码

////UDPSocket.h:

头文件

#pragmaonce

//CUDPSocket命令目标

#pragmaonce

#include"afxsock.h"

//CUDPSocket命令目标

classCUDPSocket:

publicCAsyncSocket

{

public:

CUDPSocket();

virtual~CUDPSocket();

public:

virtualvoidOnSend(intnErrorCode);

virtualvoidOnReceive(intnErrorCode);

boolBindLocatePC(DWORDm_LocateIP,intm_LocatePort);

boolSendToRemotePC(DWORDm_RemoteIP,intm_RemotePort,CStringm_SendData);

public:

boolm_fConnected;//标志变量

};

//UDPSocket.cpp

//UDPSocket.cpp:

实现文件

//

#include"stdafx.h"

#include"UDPSocket.h"

#include"UDPSocket.h"

#include"CUDPServerDlg.h"

//CUDPSocket

CUDPSocket:

:

CUDPSocket(void)

{

m_fConnected=false;

}

CUDPSocket:

:

~CUDPSocket(void)

{

}

//CUDPSocket成员函数

//事件响应函数(当一个套接字已经准备好了,并可以利用Send函数去发送数据时,就可以调用该函数去处理相应的消息)

voidCUDPSocket:

:

OnSend(intnErrorCode)

{

CCUDPServerDlg*pDl=CCUDPServerDlg:

:

GetDialog();

//pDl->OnSend(nErrorCode);

}

//事件响应函数(当一个套接字准备好了,并且可以利用Receive接收时,就可以去调用该函数去处理相应的消息)

voidCUDPSocket:

:

OnReceive(intnErrorCode)

{

CCUDPServerDlg*pDl=CCUDPServerDlg:

:

GetDialog();

pDl->OnReceive(nErrorCode);

}

//地址和端口绑定

boolCUDPSocket:

:

BindLocatePC(DWORDm_LocateIP,intm_LocatePort)

{

in_addrtempAddr;

CStringbuf;

/*

LPCTSTR类型

 L表示long指针这是为了兼容Windows3.1等16位操作系统遗留下来的,在win32中以及其他的32为操作系统中,long指针和near指针及far修饰符都是为了兼容的作用。

没有实际意义。

P表示这是一个指针;C表示是一个常量;T表示在Win32环境中,有一个_T宏,这个宏用来表示你的字符是否使用UNICODE,如果你的程序定义了UNICODE或者其他相关的宏,那么这个字符或者字符串将被作为UNICODE字符串,否则就是标准的ANSI字符串。

STR表示这个变量是一个字符串

 所以LPCTSTR就表示一个指向常固定地址的可以根据一些宏定义改变语义的字符串。

 同样,LPCSTR就只能是一个ANSI字符串,在程序中我们大部分时间要使用带T的类型定义。

 LPCTSTR==constTCHAR*==constchar*

LPCSTR与char的区别

在美国国家标准下,LPCTSTR为constchar*,是常量,不可修改;而char,是变量,可以修改。

两者的存储位置是不同的,如果强制转换的话,不安全。

*/

LPCTSTRp;

//获取本地IP

tempAddr.S_un.S_addr=htonl(m_LocateIP);

buf=inet_ntoa(tempAddr);//将网络字节的顺序的表示的IP地址转换为点分十进制表示的IP地址

p=(LPCTSTR)buf;

//绑定本地IP/*Create函数*/

if(!

Create(htons(m_LocatePort),SOCK_DGRAM,FD_READ|FD_WRITE,p))//htons函数是将16位的端口号从主机顺序装换为网络字节顺序,SOCK_DGRAM表示数据报套接字

{

returnfalse;

}

//设置连接标志

m_fConnected=true;

returntrue;

}

//向远程主机中发送数

boolCUDPSocket:

:

SendToRemotePC(DWORDm_RemoteIP,intm_RemotePort,CStringm_SendData)

{

in_addrtempAddr;

charsend_buf[1024];

CStringbuf;

LPCTSTRp;

//发送数据

if(m_fConne

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 成人教育 > 电大

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1