2024年3月22日发(作者:)

VC++下实现Socket编程方法

利用Socket编程是一类典型的网络通信程序,特别是在实时性要求比较高的

项目中,Winsock编程方法是非常实用的。下面介绍在VC 6.0环境下开发Winsock

程序的方法。

这里并没有直接应用MFC 提供的CSocket类,这是因为考虑到对于类而言,

其成员函数调用必然是完全阻塞方式的,因此只能用于人工线程中。基于这种思

想,可以在CObject类基础上派生一个套接字类,其使用方式为阻塞方式,虽然

增加了使用的条件,但可以保证其正常工作,而不会出现不加控制地使用

CSocket对象带来的冲突现象。

下面首先将具体介绍有关的套接字类的定义,新创建的套接字功能主要通过

调用CSocket的相关操作实现。

1 套接字类CBlockingSocket

首先需要定义此套接字类,在类中设置了一个属性变量:SOCKET m_hSocket;

m_hSocket 表示套接字的句柄。另外还构造了一组方法,其功能与CSocket类是

对应的,下面以创建、监听、连接建立和消息的接收和发送为例,介绍其实现方

法,。

创建

创建套接字即要求创建相应的连接,缺省类型为面向连接的流,具体实现为:

void CBlockingSocket::Create(int nType){

ASSERT(m_hSocket == NULL);

if((m_hSocket = socket(AF_INET, nType, 0)) == INVALID_SOCKET)

{

throw new CBlockingSocketException("创建套接字"); }

}

监听

Listen函数完成监听连接的任务,在实现时要求最多有10个连接请求排队,

这在一般的应用中是完全足够的。

void CBlockingSocket::Listen(){

ASSERT(m_hSocket != NULL);

if(listen(m_hSocket, 10) == SOCKET_ERROR) {

throw new CBlockingSocketException("Listen"); }

}

建立连接

连接的实际建立可以由Connect实现,同样地,缺省的建立方式为面向连接

的流。

void CBlockingSocket::Create(int nType ){

ASSERT(m_hSocket == NULL);

if((m_hSocket = socket(AF_INET, nType, 0)) == INVALID_SOCKET) {

throw new CBlockingSocketException("创建套接字"); }

}

发送消息

Send函数的作用是将数据块按一个消息发送,参数pch即为发送的消息,

nSize为消息长度,nSecs可以限制操作时间。如果客户方取消读操作,则返回

值将小于指定消息长度。

int CBlockingSocket::Send(const char* pch, const int nSize, const int

nSecs){

ASSERT(m_hSocket != NULL);

FD_SET fd = {1, m_hSocket};

TIMEVAL tv = {nSecs, 0};

if(select(0, NULL, &fd, NULL, &tv) == 0) {

throw new CBlockingSocketException("发送超时"); }

if((int nBytesSent = send(m_hSocket, pch, nSize, 0)) == SOCKET_ERROR)

{

throw new CBlockingSocketException("发送"); }

return nBytesSent;

}

此外,如果数据块比较大,可以将数据块分成多个消息发送,此工作由函数

Write完成。具体实现时将通过循环调用Send函数来实现部分消息发送,通过

对局部量nBytesThisTime 和nBytesSent的维护,保证整个数据块的正常发送。

int CBlockingSocket::Write(const char* pch, const int nSize, const int

nSecs){

int nBytesSent = 0,nBytesThisTime;

const char* pch1 = pch;

do {

nBytesThisTime = Send(pch1, nSize - nBytesSent, nSecs);

nBytesSent += nBytesThisTime;

pch1 += nBytesThisTime;

} while(nBytesSent < nSize);

return nBytesSent;

}

接收消息

Receive函数的作用是与发送消息对应的,可以将接收到的消息重组为数据

块。

int CBlockingSocket::Receive(char* pch, const int nSize, const int

nSecs){

ASSERT(m_hSocket != NULL);

FD_SET fd = {1, m_hSocket};

TIMEVAL tv = {nSecs, 0};

if(select(0, &fd, NULL, NULL, &tv) == 0) {

throw new CBlockingSocketException("接收超时"); }

if((int nBytesReceived = recv(m_hSocket, pch, nSize, 0)) ==

SOCKET_ERROR) {

throw new CBlockingSocketException("接收"); }

return nBytesReceived;

}

2 地址类CSockAddr