//
基于
select
模型的
socket
编程
#include
"stdafx.h"
#include
<winsock2.h>
#include
<iostream>
#pragma
comment
(
lib
,
"ws2_32.lib"
)
using
namespace
std
;
enum
{
MAIN_RETURN_ERROR
= -1,
MAIN_RETURN_NORMAL
= 0,
};
BOOL
CreateSocketInformation
(
SOCKET
s
);
void
FreeSocketInfomation
(
DWORD
Index
);
// WSABUF
是
WinSock2
中定义的
结构体,用于保存缓冲区的长度和地址
// struct _WSABUF
// {
// u_long len; //
缓冲区的长度
// char FAR* buf; //
缓冲区的指针
// };
const
static
int
DATA_BUF_SIZE
= 256;
struct
_SOCKET_INFOMATION
{
char
Buffer
[
DATA_BUF_SIZE
];
//
发送和接收数据缓冲区
WSABUF
DataBuf
;
//
定义发送和接收数据缓冲区,保护缓冲区在内的长度和内容
SOCKET
Socket
;
//
与客户端进行通信的
socket
DWORD
BytesSEND
;
//
保存
socket
发送字节数
DWORD
BytesRECV
;
//
保存
socket
接收字节数
};
typedef
_SOCKET_INFOMATION
SOCKET_INFOMATION
;
typedef
_SOCKET_INFOMATION
*
LPSOCKET_INFOMATION
;
const
static
int
BUF_SIZE
= 256;
DWORD
TotalSockets
= 0;
LPSOCKET_INFOMATION
SocketArray
[
FD_SETSIZE
];
int
_tmain
(
int
argc
,
_TCHAR
*
argv
[])
{
//
初始化
Winsock 2.2
WSADATA
wsaData
;
if
(
WSAStartup
(
MAKEWORD
( 2, 2 ), &
wsaData
) != 0 )
{
cout
<<
"WSAStartup
无法初始化
!"
<<
endl
;
return
MAIN_RETURN_ERROR
;
}
//
通过
WinSock
实现网络通信
SOCKET
AcceptSocket
;
SOCKET
ListenSocket
;
//
创建用于监听的
Socket
ListenSocket
=
WSASocket
(
AF_INET
,
SOCK_STREAM
, 0,
NULL
, 0,
WSA_FLAG_OVERLAPPED
);
if
(
INVALID_SOCKET
==
ListenSocket
)
{
cout
<<
"Socket Failed !"
<<
" Reson:"
<<
WSAGetLastError
()<<
endl
;
WSACleanup
();
return
MAIN_RETURN_ERROR
;
}
//
设置服务器
Socket
地址
SOCKADDR_IN
addrServ
;
addrServ
.
sin_family
=
AF_INET
;
addrServ
.
sin_port
=
htons
( 9990 );
//
服务器端口号
addrServ
.
sin_addr
.
S_un
.
S_addr
=
htonl
(
INADDR_ANY
);
//
绑定
int
retVal
;
retVal
=
bind
(
ListenSocket
, (
const
struct
sockaddr
*)&
addrServ
,
sizeof
(
SOCKADDR_IN
) );
if
(
SOCKET_ERROR
==
retVal
)
{
cout
<<
"bind failed !"
<<
" Reson: "
<<
WSAGetLastError
()<<
endl
;
closesocket
(
ListenSocket
);
WSACleanup
();
return
-1;
}
//
监听
retVal
=
listen
(
ListenSocket
, 5 );
if
(
SOCKET_ERROR
==
retVal
)
{
cout
<<
"listen failed !"
<<
" Reson:"
<<
WSAGetLastError
()<<
endl
;
closesocket
(
ListenSocket
);
WSACleanup
();
return
-1;
}
//
设置
socket
其为非阻塞模式
, argp
设为非零值
int
iModel
= 1;
retVal
=
ioctlsocket
(
ListenSocket
,
FIONBIO
, (
u_long
FAR
* )&
iModel
);
if
(
SOCKET_ERROR
==
retVal
)
{
cout
<<
"ioctlsocket failed Reson :"
<<
WSAGetLastError
()<<
endl
;
WSACleanup
();
return
MAIN_RETURN_ERROR
;
}
//
CreateSocketInformation
(
ListenSocket
);
cout
<<
"TCP Server Start ... ..."
<<
endl
;
//
循环等待
FD_SET
WriteSet
;
FD_SET
ReadSet
;
DWORD
Total
= 0;
DWORD
SendBytes
,
RecvBytes
;
while
(
true
)
{
FD_ZERO
( &
ReadSet
);
FD_ZERO
( &
WriteSet
);
FD_SET
(
ListenSocket
, &
ReadSet
);
for
(
DWORD
i
= 0;
i
<
TotalSockets
; ++
i
)
{
LPSOCKET_INFOMATION
SocketInfo
=
SocketArray
[
i
];
FD_SET
(
SocketInfo
->
Socket
, &
WriteSet
);
FD_SET
(
SocketInfo
->
Socket
, &
ReadSet
);
}
if
( (
Total
=
select
( 0, &
ReadSet
, &
WriteSet
,
NULL
,
NULL
) ) ==
SOCKET_ERROR
)
{
cout
<<
"Select Return with Error "
<<
WSAGetLastError
()<<
endl
;
return
-1;
}
for
(
DWORD
i
= 0;
i
<
TotalSockets
; ++
i
)
{
// SocketInfo
为当前要处理的信息
LPSOCKET_INFOMATION
SocketInfo
=
SocketArray
[
i
];
//
判断当前
socket
的可读性,即是否有接入的连接请求可以接收数据
if
(
FD_ISSET
(
SocketInfo
->
Socket
, &
ReadSet
) )
{
//
对于监听来说,可读表示有新的连接请求
if
(
SocketInfo
->
Socket
==
ListenSocket
)
{
Total
--;
//
接受连接请求,与客户端进行通信
if
( (
AcceptSocket
=
accept
(
ListenSocket
,
NULL
,
NULL
) ) !=
INVALID_SOCKET
)
{
int
NonBlock
= 1;
if
(
ioctlsocket
(
AcceptSocket
,
FIONBIO
, (
u_long
FAR
* )&
NonBlock
) ==
SOCKET_ERROR
)
{
cout
<<
"ioctlsocket() failed with error "
<<
WSAGetLastError
()<<
endl
;
return
-1;
}
if
(
CreateSocketInformation
(
AcceptSocket
) ==
FALSE
)
return
-1;
}
else
{
if
(
WSAGetLastError
() !=
WSAEWOULDBLOCK
)
{
cout
<<
"accept failed with error "
<<
WSAGetLastError
()<<
endl
;
return
-1;
}
}
}
//
有新的数据到达
else
{
//
如果当前在
ReadSet
集合中,表明有数据可读
if
(
FD_ISSET
(
SocketInfo
->
Socket
, &
ReadSet
) )
{
--
Total
;
memset
(
SocketInfo
->
Buffer
,
' '
,
DATA_BUF_SIZE
);
SocketInfo
->
DataBuf
.
buf
=
SocketInfo
->
Buffer
;
SocketInfo
->
DataBuf
.
len
=
DATA_BUF_SIZE
;
//
接收数据
DWORD
Flags
= 0;
if
(
WSARecv
(
SocketInfo
->
Socket
, &(
SocketInfo
->
DataBuf
), 1, &
RecvBytes
, &
Flags
,
NULL
,
NULL
) ==
SOCKET_ERROR
)
{
if
(
WSAEWOULDBLOCK
!=
WSAGetLastError
() )
{
cout
<<
"WSARecv failed with error "
<<
WSAGetLastError
()<<
endl
;
FreeSocketInfomation
(
i
);
}
continue
;
}
else
{
SocketInfo
->
BytesRECV
=
RecvBytes
;
if
(
RecvBytes
== 0 )
{
FreeSocketInfomation
(
i
);
continue
;
}
else
{
cout
<<
SocketInfo
->
DataBuf
.
buf
<<
endl
;
}
}
}
}
}
else
{
//
发送数据
if
(
FD_ISSET
(
SocketInfo
->
Socket
, &
WriteSet
) )
{
--
Total
;
SocketInfo
->
DataBuf
.
buf
=
SocketInfo
->
Buffer
+
SocketInfo
->
BytesSEND
;
SocketInfo
->
DataBuf
.
len
=
SocketInfo
->
BytesRECV
-
SocketInfo
->
BytesSEND
;
if
(
SocketInfo
->
DataBuf
.
len
> 0 )
{
if
(
WSASend
(
SocketInfo
->
Socket
, &(
SocketInfo
->
DataBuf
), 1, &
SendBytes
, 0,
NULL
,
NULL
) ==
SOCKET_ERROR
)
{
if
(
WSAGetLastError
() !=
WSAEWOULDBLOCK
)
{
cout
<<
"WSASend failed with error "
<<
WSAGetLastError
()<<
endl
;
FreeSocketInfomation
(
i
);
}
continue
;
}
else
{
SocketInfo
->
BytesSEND
+=
SendBytes
;
if
(
SocketInfo
->
BytesSEND
==
SocketInfo
->
BytesRECV
)
{
SocketInfo
->
BytesRECV
= 0;
SocketInfo
->
BytesSEND
= 0;
}
}
}
}
}
}
}
//
最后做一些清理工作
closesocket
(
ListenSocket
);
closesocket
(
AcceptSocket
);
WSACleanup
();
system
(
"pause"
);
return
MAIN_RETURN_NORMAL
;
}
//
创建
SOCKET
BOOL
CreateSocketInformation
(
SOCKET
s
)
{
LPSOCKET_INFOMATION
SI
;
//
为
SI
分配空间
if
( (
SI
= (
LPSOCKET_INFOMATION
)
GlobalAlloc
(
GPTR
,
sizeof
(
SOCKET_INFOMATION
) ) ) ==
NULL
)
{
cout
<<
"GlobalAlloc Failed with Error "
<<
GetLastError
();
return
FALSE
;
}
SI
->
Socket
=
s
;
SI
->
BytesSEND
= 0;
SI
->
BytesRECV
= 0;
SocketArray
[
TotalSockets
] =
SI
;
++
TotalSockets
;
return
TRUE
;
}
void
FreeSocketInfomation
(
DWORD
Index
)
{
LPSOCKET_INFOMATION
SI
=
SocketArray
[
Index
];
DWORD
i
;
closesocket
(
SI
->
Socket
);
GlobalFree
(
SI
);
for
(
i
=
Index
;
i
<
TotalSockets
; ++
i
)
SocketArray
[
i
] =
SocketArray
[
i
+1];
--
TotalSockets
;
}
客户端1:
客户端2
服务器:
没有实现收到 服务端把数据发回客户端。