注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Mihooke's blog

IT之恋

 
 
 

日志

 
 

select实现多个client连接  

2017-05-13 19:50:18|  分类: C++ |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
利用select实现server和多个client实现通信。Master作为server,Worker和PLCWorker作为client。select函数在listen和accept中间使用

Master.cpp

#include <iostream>
#include <WinSock2.h>
#include <tchar.h>
using namespace std;
#pragma comment(lib, "ws2_32.lib")

int main()
{
WORD wVersionRequsted;
WSADATA wsaData;
wVersionRequsted = MAKEWORD(2, 2);
int nErr = WSAStartup(wVersionRequsted, &wsaData);
if (nErr != 0)
{
WSACleanup();
return 1;
}
if (LOBYTE(wsaData.wVersion) != 2 && HIBYTE(wsaData.wVersion) != 2)
{
WSACleanup();
return 2;
}

SOCKET sockMaster = socket(AF_INET, SOCK_STREAM, 0);
if (INVALID_SOCKET == sockMaster)
{
WSACleanup();
return 3;
}
SOCKADDR_IN addrMaster;
addrMaster.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
addrMaster.sin_family = AF_INET;
addrMaster.sin_port = htons(1324);

// setsockopt() 设置socket和一个已使用的地址绑定
BOOL isOpt = FALSE;
int nRet = 0;
nRet = setsockopt(sockMaster, SOL_SOCKET, SO_REUSEADDR, (char*)&isOpt, sizeof(isOpt));
if (SOCKET_ERROR == nRet)
{
closesocket(sockMaster);
WSACleanup();
return 4;
}

nRet = bind(sockMaster, (SOCKADDR*)&addrMaster, sizeof(SOCKADDR));
if (SOCKET_ERROR == nRet)
{
closesocket(sockMaster);
WSACleanup();
return 5;
}

listen(sockMaster, 10);

SOCKET sockWorker;
SOCKADDR_IN addrWorker;
int nLen = sizeof(SOCKADDR);

SOCKADDR_IN addrTempWorker;
int nTempLen = sizeof(SOCKADDR);

fd_set fs;
FD_ZERO(&fs);
FD_SET(sockMaster, &fs);


while (1)
{
fd_set fsOld = fs;
// 在listen和accept之间使用select
int nRet = select(sockMaster, &fsOld, NULL, NULL, NULL);
if (nRet == SOCKET_ERROR)
{
Sleep(1000);
continue;
}

// 轮询每个socket
for (unsigned int i=0; i<fs.fd_count; i++)
{
if (FD_ISSET(fs.fd_array[i], &fsOld))
{
if (fs.fd_array[i] == sockMaster)
{
memset(&addrWorker, 0, sizeof(SOCKADDR));
sockWorker = accept(sockMaster, (SOCKADDR*)&addrWorker, &nLen);
if (sockWorker != INVALID_SOCKET)
{
FD_SET(sockWorker, &fs);
cout<<"client : "<<inet_ntoa(addrWorker.sin_addr)<<" "<<\
ntohs(addrWorker.sin_port)<<" connd!\n";
}
}
else
{
char cBufRecv[20] = {0};
recv(fs.fd_array[i], cBufRecv, 20, 0);
cout<<"recv msg :"<<cBufRecv<<endl;
memset(&addrTempWorker, 0, sizeof(SOCKADDR));
getpeername(fs.fd_array[i], (SOCKADDR*)&addrTempWorker, &nTempLen);
string strIP = inet_ntoa(addrTempWorker.sin_addr);
if (!strIP.compare("127.0.0.1"))
{
send(fs.fd_array[i], "127.0.0.1 msg", 13, 0);
}
}
}
}
}

closesocket(sockMaster);
WSACleanup();
return 0;
}

Worker1.cpp

#include <iostream>
#include <WinSock2.h>
#include <tchar.h>
using namespace std;
#pragma comment(lib, "ws2_32.lib")

int main()
{
WORD wVersionRequsted;
WSADATA wsaData;
wVersionRequsted = MAKEWORD(2, 2);
int nErr = WSAStartup(wVersionRequsted, &wsaData);
if (nErr != 0)
{
WSACleanup();
return 1;
}
if (LOBYTE(wsaData.wVersion) != 2 && HIBYTE(wsaData.wVersion) != 2)
{
WSACleanup();
return 2;
}

SOCKET sockWorker = socket(AF_INET, SOCK_STREAM, 0);
if (INVALID_SOCKET == sockWorker)
{
WSACleanup();
return 3;
}
SOCKADDR_IN addrWorker;
addrWorker.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
addrWorker.sin_family = AF_INET;
addrWorker.sin_port = htons(1324);

int nRet = 0;
nRet = connect(sockWorker, (SOCKADDR*)&addrWorker, sizeof(SOCKADDR));
if (SOCKET_ERROR == nRet)
{
closesocket(sockMaster);
WSACleanup();
return 4;
}

send(sockWorker, "worker", 6, 0);
char cBufRecv[20] = {0};
recv(sockWorker, cBufRecv, 20, 0);
cout<<cBufRecv<<endl;
while (1)
{
}

closesocket(sockWorker);
WSACleanup();
return 0;
}

Worker2.cpp

#include <iostream>
#include <WinSock2.h>
#include <tchar.h>
using namespace std;
#pragma comment(lib, "ws2_32.lib")

int main()
{
WORD wVersionRequsted;
WSADATA wsaData;
wVersionRequsted = MAKEWORD(2, 2);
int nErr = WSAStartup(wVersionRequsted, &wsaData);
if (nErr != 0)
{
WSACleanup();
return 1;
}
if (LOBYTE(wsaData.wVersion) != 2 && HIBYTE(wsaData.wVersion) != 2)
{
WSACleanup();
return 2;
}

SOCKET sockPLCWorker = socket(AF_INET, SOCK_STREAM, 0);
if (INVALID_SOCKET == sockPLCWorker)
{
WSACleanup();
return 3;
}
SOCKADDR_IN addrPLCWorker;
addrPLCWorker.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
addrPLCWorker.sin_family = AF_INET;
addrPLCWorker.sin_port = htons(1324);

int nRet = 0;
nRet = connect(sockPLCWorker, (SOCKADDR*)&addrPLCWorker, sizeof(SOCKADDR));
if (SOCKET_ERROR == nRet)
{
closesocket(sockPLCWorker);
WSACleanup();
return 4;
}
send(sockPLCWorker, "PLCWorker", 9, 0);
char cBufRecv[20] = {0};
recv(sockPLCWorker, cBufRecv, 20, 0);
cout<<cBufRecv<<endl;
while (1)
{
}

closesocket(sockPLCWorker);
WSACleanup();
return 0;
}

运行结果:
select实现多个client连接 - mihooke - Mihookes blog
 
select函数参数介绍
int select(
  int nfds,
  fd_set FAR* readfds,
  fd_set FAR* writefds,
  fd_set FAR* exceptfds,
  const struct timeval FAR* timeout
);

nfds: 本参数忽略,仅起到兼容作用。

fd_set* readfds: 是指向fd_set结构的指针,这个集合中应该包括文件描述符,我们是要监视这些文件描述符的读变化的,即我们关心是否可以从这些文件中读取数据了,如果这个集合中有一个文件可读,select就会返回一个大于0的值,表示有文件可读,如果没有可读的文件,则根据timeout参数再判断是否超时,若超出timeout的时间,select返回0,若发生错误返回负值。可以传入NULL值,表示不关心任何文件的读变化。

fd_set*writefds: 是指向fd_set结构的指针,这个集合中应该包括文件描述符,我们是要监视这些文件描述符的写变化的,即我们关心是否可以向这些文件中写入数据了,如果这个集合中有一个文件可写,select就会返回一个大于0的值,表示有文件可写,如果没有可写的文件,则根据timeout参数再判断是否超时,若超出timeout的时间,select返回0,若发生错误返回负值。可以传入NULL值,表示不关心任何文件的写变化。

fd_set *errorfds: 同上面两个参数的意图,用来监视文件错误异常。

struct timeval *timeout: 是select的超时时间,这个参数至关重要,它可以使select处于三种状态,第一,若将NULL以形参传入,即不传入时间结构,就是将select置于阻塞状态,一定等到监视文件描述符集合中某个文件描述符发生变化为止;第二,若将时间值设为0秒0毫秒,就变成一个纯粹的非阻塞函数,不管文件描述符是否有变化,都立刻返回继续执行,文件无变化返回0,有变化返回一个正值;第三,timeout的值大于0,这就是等待的超时时间,即select在timeout时间内阻塞,超时时间之内有事件到来就返回了,否则在超时后不管怎样一定返回,返回值同上述。
structtimeval{
  long tv_sec;//seconds
  long tv_usec;//mill seconds
};
  评论这张
 
阅读(30)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017