C++socket编程Word文档格式.docx
- 文档编号:21405523
- 上传时间:2023-01-30
- 格式:DOCX
- 页数:63
- 大小:344.25KB
C++socket编程Word文档格式.docx
《C++socket编程Word文档格式.docx》由会员分享,可在线阅读,更多相关《C++socket编程Word文档格式.docx(63页珍藏版)》请在冰豆网上搜索。
因此,TCP提供了可靠的应用数据传输服务。
通信双方使用TCP传输的一般过程参考如图3.2。
图3.2TCP通信的一般过程
本节将要实现一个TCP传输的演示程序TCPDemo,它包括服务器和客户机两个部分。
它们的程序界面如图3.3。
图3.3TCP传输演示程序界面
TCPDemo的演示过程如下:
(1)将服务器和客户机两部分程序都运行起来(此时服务器已经启动了侦听客户机连接请求的子线程,侦听端口号为10028)。
(2)在客户机程序界面上输入服务器的IP地址(如果服务器和客户机运行在同一台机器上,IP地址可以指定为127.0.0.1)、侦听端口号(因为服务器在10028端口上侦听,这里也应该指定为10028)。
(3)点击客户机程序界面上的“Connect”按钮,向服务器发送Socket连接请求。
(4)服务器侦听到有客户机的连接请求后便接受它(于是在两个程序之间就建立了一条可靠的Socket连接)。
然后服务器会向客户机发送两次字符串数据。
(5)客户机接收到数据后,弹出两次如图3.4的消息框。
图3.4TCP传输客户机接收到数据后显示的消息框
TCPDemo为什么使用10028作为TCP通信的端口号?
因为TCP数据包的TCP头结构中,使用了16位的域来表示一个端口号。
因此,有65536个可能的端口号。
不过,0-1023是周知口(众所周知的端口,比如80是超文本传输协议http的端口,25是简单邮件传输协议smtp的端口,20和21是文件传输协议ftp的端口等),比1023大的端口号通常被称为高端口号。
应用程序一般使用高端口号提供自己的通信服务。
TCPDemo使用10028端口是偶然的,只要比1023大就可以了。
TCPDemo在具体实现时,设计了一个CTCPListener类专门用于服务器对特定TCP端口的侦听。
另外,设计了一个CStreamSocket类专门用于TCP数据的传输。
CStreamSocket作为基类,服务器程序从它派生出另一个类CSocketSender专门用于数据的发送,客户机程序从它派生出CSocketReceiver类专门用于数据的接收。
这些类的继承结构如图3.5。
图3.5TCPDemo的类继承结构
关于CMsgStation和CMsgReceiver两个类的功能介绍,请读者另行参考本书的“2.4.1一种不错的设计模式”。
//
//CTCPListener.h
#ifndef__H_CTCPListener__
#define__H_CTCPListener__
#include"
CMsgStation.h"
classCTCPListener:
publicCMsgStation
{
protected:
SOCKETmListener;
//用于侦听的Socket
SOCKETmAccepted;
//用于与远程端建立连接的Socket
WORDmListenPort;
//侦听端口号
BOOLmIsListening;
//是否正在侦听的标记
HANDLEmLsnThread;
//侦听线程
public:
CTCPListener();
virtual~CTCPListener();
//设置/得到侦听的端口号
voidSetListenPort(WORDinPort);
WORDGetListenPort(void);
//创建/销毁用于侦听的Socket
BOOLCreate(void);
voidDeleteListener(void);
//销毁服务器与客户机建立连接的Socket
voidDeleteAccepted(void);
//启动/停止侦听线程
BOOLStartListening(void);
voidStopListening(void);
//得到服务器与客户机建立连接的Socket(用于数据传输)
SOCKETGetAccepted(void);
private:
BOOLAccept(void);
//接受远程端的连接请求
staticDWORDWINAPIListeningThrd(void*pParam);
//侦听线程执行体
};
#endif//__H_CTCPListener__
//
//CTCPListener.cpp
stdafx.h"
CTCPListener.h"
Netdefs.h"
#ifdef_DEBUG
#definenewDEBUG_NEW
#undefTHIS_FILE
staticcharTHIS_FILE[]=__FILE__;
#endif
//////////////////////////////////////////////////////////////////////////////
CTCPListener:
:
CTCPListener()
//参数初始化
mListener=INVALID_SOCKET;
mAccepted=INVALID_SOCKET;
//默认在10028端口上侦听
mListenPort=10028;
mLsnThread=NULL;
mIsListening=FALSE;
}
~CTCPListener()
//销毁Socket
DeleteAccepted();
DeleteListener();
//停止侦听线程
StopListening();
//设置侦听端口号
voidCTCPListener:
SetListenPort(WORDinPort)
mListenPort=inPort;
//得到侦听端口号
WORDCTCPListener:
GetListenPort(void)
returnmListenPort;
//创建用于侦听的Socket
BOOLCTCPListener:
Create(void)
//销毁侦听Socket
intval=0;
BOOLpass=FALSE;
//创建一个TCP传输的Socket
mListener=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
if(mListener!
=INVALID_SOCKET)
{
//在Socket上进行参数设置
BOOLsopt=TRUE;
setsockopt(mListener,IPPROTO_TCP,TCP_NODELAY,
(char*)&
sopt,sizeof(BOOL));
//在销毁Socket时不必等待未发送完的数据完全发送出去
setsockopt(mListener,SOL_SOCKET,SO_DONTLINGER,
//绑定Socket到指定的侦听端口
SOCKADDR_INaddr;
memset(&
addr,0,sizeof(SOCKADDR_IN));
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=htonl(INADDR_ANY);
addr.sin_port=htons(mListenPort);
val=bind(mListener,(structsockaddr*)&
addr,sizeof(addr));
pass=(val!
=SOCKET_ERROR);
}
if(pass)
//将Socket置于侦听状态
val=listen(mListener,SOMAXCONN);
if(!
pass)
DeleteListener();
returnpass;
//销毁用于侦听的Socket
DeleteListener(void)
closesocket(mListener);
mListener=INVALID_SOCKET;
//销毁服务器与客户机建立连接的Socket
DeleteAccepted(void)
if(mAccepted!
closesocket(mAccepted);
mAccepted=INVALID_SOCKET;
//启动侦听线程(因为用于接受连接请求的accept函数调用时会阻塞)
StartListening(void)
//如果侦听Socket没有创建,则创建它
if(mListener==INVALID_SOCKET)
Create();
if(mIsListening)
{
returnTRUE;
}
//启动侦听线程
DWORDthreadID=0;
mLsnThread=CreateThread(NULL,0,ListeningThrd,
this,0,&
threadID);
return(mLsnThread!
=NULL);
returnFALSE;
//停止侦听线程
StopListening(void)
=INVALID_SOCKET&
&
mIsListening)
//销毁侦听Socket,于是accept将脱离阻塞状态
//等待侦听线程完全退出
if(mLsnThread!
=NULL)
WaitForSingleObject(mLsnThread,INFINITE);
mLsnThread=NULL;
//接受远程端的连接请求(创建一个新的Socket用于与远程端建立一条连接)
Accept(void)
SOCKADDR_INsaddr;
intlen=sizeof(SOCKADDR_IN);
//侦听远程端的连接请求(如果没有连接请求,这个函数将阻塞)
SOCKETaccepted=accept(mListener,(SOCKADDR*)&
saddr,&
len);
if(accepted==INVALID_SOCKET)
returnFALSE;
//注意:
目前仅支持建立一条Socket连接!
//在建立新的连接之前将以前的连接断开
DeleteAccepted();
//保存与远程端建立连接的Socket
mAccepted=accepted;
//在Socket上设置一些参数
setsockopt(mAccepted,IPPROTO_TCP,TCP_NODELAY,
setsockopt(mAccepted,SOL_SOCKET,SO_DONTLINGER,
returnTRUE;
//当与远程端连接的Socket取出之后,保存该Socket的变量置为无效
//取出的Socket由取出者负责销毁
SOCKETCTCPListener:
GetAccepted(void)
SOCKETret=mAccepted;
returnret;
//侦听线程的函数执行体
DWORDWINAPICTCPListener:
ListeningThrd(void*pParam)
ASSERT(pParam);
//获得侦听对象指针
CTCPListener*pListen=(CTCPListener*)pParam;
pListen->
mIsListening=TRUE;
while(pListen->
mIsListening)
//开始侦听(如果没有远程端发送连接请求,这个函数将阻塞)
if(!
pListen->
Accept())
pListen->
mIsListening=FALSE;
break;
else
//constlongcNewSocketAccepted=6688;
//发送给上层观察者一个自定义消息cNewSocketAccepted,
//表示一条Socket连接已经建立(可以用它进行数据传输了!
)
Broadcast(cNewSocketAccepted);
return1;
//CStreamSocket.h
#ifndef__H_CStreamSocket__
#define__H_CStreamSocket__
classCStreamSocket
SOCKETmSocket;
//用于数据发送或接收的Socket
BOOLmIsConnected;
//Socket是否已经建立了连接的标记
BOOLmIsReceiving;
//使用独立的线程进行数据接收
HANDLEmRcvThread;
BOOLmIsSending;
//使用独立的线程进行数据发送
HANDLEmSndThread;
CStreamSocket();
virtual~CStreamSocket();
BOOLAttach(SOCKETinSocket);
//关联一个Socket
voidDetach(void);
//向指定IP地址、端口号的机器发送连接请求
BOOLConnectTo(constchar*inTarget,WORDinPort);
BOOLIsConnected(void){returnmIsConnected;
};
//用于数据接收的控制函数
BOOLStartReceiving(void);
voidStopReceiving(void);
BOOLIsReceiving(void){returnmIsReceiving;
//用于数据发送的控制函数
BOOLStartSending(void);
voidStopSending(void);
BOOLIsSending(void){returnmIsSending;
staticDWORDWINAPIReceivingThrd(void*pParam);
//接收线程执行体
staticDWORDWINAPISendingThrd(void*pParam);
//发送线程执行体
//接收/发送数据循环过程(虚函数,供子类定制)
virtualvoidReceivingLoop(void);
virtualvoidSendingLoop(void);
#endif//__H_CStreamSocket__
//CStreamSocket.cpp
CStreamSocket.h"
UNetwork.h"
CStreamSocket:
CStreamSocket()
{
mSocket=INVALID_SOCKET;
mIsConnected=FALSE;
mIsReceiving=FALSE;
mIsSending=FALSE;
mRcvThread=NULL;
mSndThread=NULL;
//销毁Socket,停止发送/接收线程
~CStreamSocket()
Detach();
StopSending();
StopReceiving();
//关联一个Socket到本包装对象
BOOLCStreamSocket:
Attach(SOCKETinSocket)
//如果已经包装了一个Socket,则返回一个错误值
if(mSocket!
returnFALSE;
//保存Socket句柄
mSocket=inSocket;
mIsConnected=TRUE;
returnTRUE;
//销毁Socket
voidCStreamSocket:
Detach(void)
closesocket(mSocket);
mSocket=INVALID_SOCKET;
mIsConnected=FALSE;
//向指定IP地址、端口号的机器发送连接请求
ConnectTo(constchar*inTarget,WORDinPort)
if(mIsConnected)
//首先创建一个TCP传输的Socket
mSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
//在成功创建的Socket上调整参数
setsockopt(mSocket,IPPROTO_TCP,TCP_NODELAY,
setsockopt(mSocket,SOL_SOCKET,SO_DONTLINGER,
//向服务器发送连接请求
saddr,0,sizeof(SOCKADDR_IN));
saddr.sin_addr.S_un.S_addr=inet_addr(inTarget);
saddr.sin_family=AF_INET;
saddr.sin
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- socket 编程