C++socket编程.docx

上传人:b****6 文档编号:13090512 上传时间:2023-06-11 格式:DOCX 页数:75 大小:344.20KB
下载 相关 举报
C++socket编程.docx_第1页
第1页 / 共75页
C++socket编程.docx_第2页
第2页 / 共75页
C++socket编程.docx_第3页
第3页 / 共75页
C++socket编程.docx_第4页
第4页 / 共75页
C++socket编程.docx_第5页
第5页 / 共75页
C++socket编程.docx_第6页
第6页 / 共75页
C++socket编程.docx_第7页
第7页 / 共75页
C++socket编程.docx_第8页
第8页 / 共75页
C++socket编程.docx_第9页
第9页 / 共75页
C++socket编程.docx_第10页
第10页 / 共75页
C++socket编程.docx_第11页
第11页 / 共75页
C++socket编程.docx_第12页
第12页 / 共75页
C++socket编程.docx_第13页
第13页 / 共75页
C++socket编程.docx_第14页
第14页 / 共75页
C++socket编程.docx_第15页
第15页 / 共75页
C++socket编程.docx_第16页
第16页 / 共75页
C++socket编程.docx_第17页
第17页 / 共75页
C++socket编程.docx_第18页
第18页 / 共75页
C++socket编程.docx_第19页
第19页 / 共75页
C++socket编程.docx_第20页
第20页 / 共75页
亲,该文档总共75页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

C++socket编程.docx

《C++socket编程.docx》由会员分享,可在线阅读,更多相关《C++socket编程.docx(75页珍藏版)》请在冰点文库上搜索。

C++socket编程.docx

C++socket编程

第3章网络应用

3.1网络编程基础

多媒体技术与网络技术的结合,使得网络生活变得多姿多彩。

从此,网络生活很迷人;网络改变了和改变着人们原本的生活方式。

姑且认为DirectShow是单机的多媒体技术,一旦融合了网络技术,DirectShow更显现了它强大的生命力。

本章将着重介绍DirectShow技术在网络方面的应用。

网络编程,当然要用到WindowsSocket(套接字)技术。

Socket相关的操作由一系列API函数来完成,比如socket、bind、listen、connect、accept、send、sendto、recv、recvfrom等。

调用这些API函数有一定的先后次序,有些函数的参数还比较复杂,对于开发者来说,不是很好用。

于是,微软的MFC提供了两个类:

CAsyncSocket和CSocket,极大地方便了Socket功能的使用。

这两个类的继承关系如图3.1。

图3.1MFCSocket类的继承关系

CAsyncSocket类在较低层次上封装了WindowsSocketAPI,并且通过内建一个(隐藏的)窗口,实现了适合Windows应用的异步机制(WindowsSocketAPI默认情况下工作在阻塞模式,不方便直接在消息驱动的Windows程序上使用)。

CSocket类从CAsyncSocket类派生,进一步简化了Socket功能的应用。

不过很遗憾,正因为这两个类都内建了一个窗口,它们并不是线程安全的(thread-safe);如果要在多线程环境下应用Socket功能,建议自行封装SocketAPI函数。

使用Socket传输数据主要有两种方式:

TCP传输和UDP传输。

(OSI参考模型将网络通信分成7个层次,从低往上依次为物理层、数据链路层、网络层、传输层、会话层、表示层、应用层;TCP和UDP均是传输层的协议。

)下面,就分别来介绍这两种数据传输方式。

提示:

本章在介绍网络通信双方的时候,会使用两组关键词:

服务器-客户机和本地端-远程端。

其中,服务器-客户机是根据角色来界定的;而本地端-远程端是一个相对概念,依据不同的参照物,可以分别表示不同的角色。

比如以服务器为参照物,可以称服务器为本地端,称客户机为远程端;而如果以客户机为参照物,可以称客户机为本地端,称服务器为远程端。

3.1.1TCP传输

TCP,TransferControlProtocol的缩写(传输控制协议),是一种面向连接的网络传输协议。

TCP协议的特点是,支持多数据流操作,提供流控和错误控制,甚至能完成对乱序到达报文的重新排序等。

因此,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();

public:

//设置/得到侦听的端口号

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

//

#include"stdafx.h"

#include"CTCPListener.h"

#include"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:

:

~CTCPListener()

{

//销毁Socket

DeleteAccepted();

DeleteListener();

//停止侦听线程

StopListening();

}

//设置侦听端口号

voidCTCPListener:

:

SetListenPort(WORDinPort)

{

mListenPort=inPort;

}

//得到侦听端口号

WORDCTCPListener:

:

GetListenPort(void)

{

returnmListenPort;

}

//创建用于侦听的Socket

BOOLCTCPListener:

:

Create(void)

{

DeleteListener();//销毁侦听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,

(char*)&sopt,sizeof(BOOL));

//绑定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);

pass=(val!

=SOCKET_ERROR);

}

if(!

pass)

{

DeleteListener();

}

returnpass;

}

//销毁用于侦听的Socket

voidCTCPListener:

:

DeleteListener(void)

{

if(mListener!

=INVALID_SOCKET)

{

closesocket(mListener);

mListener=INVALID_SOCKET;

}

}

//销毁服务器与客户机建立连接的Socket

voidCTCPListener:

:

DeleteAccepted(void)

{

if(mAccepted!

=INVALID_SOCKET)

{

closesocket(mAccepted);

mAccepted=INVALID_SOCKET;

}

}

//启动侦听线程(因为用于接受连接请求的accept函数调用时会阻塞)

BOOLCTCPListener:

:

StartListening(void)

{

//如果侦听Socket没有创建,则创建它

if(mListener==INVALID_SOCKET)

{

Create();

}

if(mListener!

=INVALID_SOCKET)

{

if(mIsListening)

{

returnTRUE;

}

//启动侦听线程

DWORDthreadID=0;

mLsnThread=CreateThread(NULL,0,ListeningThrd,

this,0,&threadID);

return(mLsnThread!

=NULL);

}

returnFALSE;

}

//停止侦听线程

voidCTCPListener:

:

StopListening(void)

{

if(mListener!

=INVALID_SOCKET&&mIsListening)

{

//销毁侦听Socket,于是accept将脱离阻塞状态

DeleteListener();

//等待侦听线程完全退出

if(mLsnThread!

=NULL)

{

WaitForSingleObject(mLsnThread,INFINITE);

mLsnThread=NULL;

}

}

}

//接受远程端的连接请求(创建一个新的Socket用于与远程端建立一条连接)

BOOLCTCPListener:

:

Accept(void)

{

if(mListener!

=INVALID_SOCKET)

{

SOCKADDR_INsaddr;

intlen=sizeof(SOCKADDR_IN);

//侦听远程端的连接请求(如果没有连接请求,这个函数将阻塞)

SOCKETaccepted=accept(mListener,(SOCKADDR*)&saddr,&len);

if(accepted==INVALID_SOCKET)

{

returnFALSE;

}

//注意:

目前仅支持建立一条Socket连接!

//在建立新的连接之前将以前的连接断开

DeleteAccepted();

//保存与远程端建立连接的Socket

mAccepted=accepted;

//在Socket上设置一些参数

BOOLsopt=TRUE;

setsockopt(mAccepted,IPPROTO_TCP,TCP_NODELAY,

(char*)&sopt,sizeof(BOOL));

setsockopt(mAccepted,SOL_SOCKET,SO_DONTLINGER,

(char*)&sopt,sizeof(BOOL));

returnTRUE;

}

returnFALSE;

}

//当与远程端连接的Socket取出之后,保存该Socket的变量置为无效

//取出的Socket由取出者负责销毁

SOCKETCTCPListener:

:

GetAccepted(void)

{

SOCKETret=mAccepted;

mAccepted=INVALID_SOCKET;

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连接已经建立(可以用它进行数据传输了!

pListen->Broadcast(cNewSocketAccepted);

}

}

return1;

}

//

//CStreamSocket.h

//

#ifndef__H_CStreamSocket__

#define__H_CStreamSocket__

classCStreamSocket

{

protected:

SOCKETmSocket;//用于数据发送或接收的Socket

BOOLmIsConnected;//Socket是否已经建立了连接的标记

BOOLmIsReceiving;//使用独立的线程进行数据接收

HANDLEmRcvThread;

BOOLmIsSending;//使用独立的线程进行数据发送

HANDLEmSndThread;

public:

CStreamSocket();

virtual~CStreamSocket();

public:

BOOLAttach(SOCKETinSocket);//关联一个Socket

voidDetach(void);//销毁Socket

//向指定IP地址、端口号的机器发送连接请求

BOOLConnectTo(constchar*inTarget,WORDinPort);

BOOLIsConnected(void){returnmIsConnected;};

//用于数据接收的控制函数

BOOLStartReceiving(void);

voidStopReceiving(void);

BOOLIsReceiving(void){returnmIsReceiving;};

//用于数据发送的控制函数

BOOLStartSending(void);

voidStopSending(void);

BOOLIsSending(void){returnmIsSending;};

protected:

staticDWORDWINAPIReceivingThrd(void*pParam);//接收线程执行体

staticDWORDWINAPISendingThrd(void*pParam);//发送线程执行体

//接收/发送数据循环过程(虚函数,供子类定制)

virtualvoidReceivingLoop(void);

virtualvoidSendingLoop(void);

};

#endif//__H_CStreamSocket__

//

//CStreamSocket.cpp

//

#include"stdafx.h"

#include"CStreamSocket.h"

#include"UNetwork.h"

#ifdef_DEBUG

#definenewDEBUG_NEW

#undefTHIS_FILE

staticcharTHIS_FILE[]=__FILE__;

#endif

//////////////////////////////////////////////////////////////////////////////

CStreamSocket:

:

CStreamSocket()

{

//参数初始化

mSocket=INVALID_SOCKET;

mIsConnected=FALSE;

mIsReceiving=FALSE;

mIsSending=FALSE;

mRcvThread=NULL;

mSndThread=NULL;

}

//销毁Socket,停止发送/接收线程

CStreamSocket:

:

~CStreamSocket()

{

Detach();

StopSending();

StopReceiving();

}

//关联一个Socket到本包装对象

BOOLCStreamSocket:

:

Attach(SOCKETinSocket)

{

//如果已经包装了一个Socket,则返回一个错误值

if(mSocket!

=INVALID_SOCKET)

{

returnFALSE;

}

//保存Socket句柄

mSocket=inSocket;

mIsConnected=TRUE;

returnTRUE;

}

//销毁Socket

voidCStreamSocket:

:

Detach(void)

{

if(mSocket!

=INVALID_SOCKET)

{

closesocket(mSocket);

mSocket=INVALID_SOCKET;

mIsConnected=FALSE;

}

}

//向指定IP地址、端口号的机器发送连接请求

BOOLCStreamSocket:

:

ConnectTo(constchar*inTarget,WORDinPort)

{

if(mIsConnected)

{

returnTRUE;

}

//首先创建一个TCP传输的Socket

mSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

if(mSocket!

=INVALID_SOCKET)

{

//在成功创建的Socket上调整参数

BOOLsopt=TRUE;

setsockopt(mSocket,IPPROTO_TCP,TCP_NODELAY,

(char*)&sopt,sizeof(BOOL));

setsockopt(mSocket,SOL_SOCKET,SO_DONTLINGER,

(char*)&sopt,sizeof(BOOL));

//向服务器发送连接请求

SOCKADDR_INsaddr;

memset(&saddr,0,sizeof(SOCKADDR_IN));

saddr.sin_addr.S_un.S_addr=inet_addr(inTarget);

saddr.sin_family=AF_INET;

saddr.sin

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

当前位置:首页 > 经管营销 > 经济市场

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2