C++ Winsock服务器向每个客户端发送消息
如何将此echo服务器转换为聊天服务器?我想让这个程序做的是让服务器将收到的每一条消息发送给每一个客户端。我想应该有某种队列,但我对实现这一点一无所知。代码示例将非常有用。代码如下: 服务器:C++ Winsock服务器向每个客户端发送消息,c++,multithreading,server,winsock,C++,Multithreading,Server,Winsock,如何将此echo服务器转换为聊天服务器?我想让这个程序做的是让服务器将收到的每一条消息发送给每一个客户端。我想应该有某种队列,但我对实现这一点一无所知。代码示例将非常有用。代码如下: 服务器: #include <winsock2.h> #include <iostream> using namespace std; struct CLIENT_INFO { SOCKET hClientSocket ; struct sockaddr_in client
#include <winsock2.h>
#include <iostream>
using namespace std;
struct CLIENT_INFO
{
SOCKET hClientSocket ;
struct sockaddr_in clientAddr ;
} ;
char szServerIPAddr[ ] = "192.168.1.221" ; // Put here the IP address of the server
int nServerPort = 5050 ; // The server port that will be used by
// clients to talk with the server
bool InitWinSock2_0( ) ;
BOOL WINAPI ClientThread( LPVOID lpData ) ;
int main( )
{
if ( ! InitWinSock2_0( ) )
{
cout << "Unable to Initialize Windows Socket environment" << WSAGetLastError( ) << endl ;
return -1 ;
}
SOCKET hServerSocket ;
hServerSocket = socket(
AF_INET, // The address family. AF_INET specifies TCP/IP
SOCK_STREAM, // Protocol type. SOCK_STREM specified TCP
0 // Protoco Name. Should be 0 for AF_INET address family
) ;
if ( hServerSocket == INVALID_SOCKET )
{
cout << "Unable to create Server socket" << endl ;
// Cleanup the environment initialized by WSAStartup()
WSACleanup( ) ;
return -1 ;
}
// Create the structure describing various Server parameters
struct sockaddr_in serverAddr ;
serverAddr . sin_family = AF_INET ; // The address family. MUST be AF_INET
serverAddr . sin_addr . s_addr = inet_addr( szServerIPAddr ) ;
serverAddr . sin_port = htons( nServerPort ) ;
// Bind the Server socket to the address & port
if ( bind( hServerSocket, ( struct sockaddr * ) &serverAddr, sizeof( serverAddr ) ) == SOCKET_ERROR )
{
cout << "Unable to bind to " << szServerIPAddr << " port " << nServerPort << endl ;
// Free the socket and cleanup the environment initialized by WSAStartup()
closesocket( hServerSocket ) ;
WSACleanup( ) ;
return -1 ;
}
// Put the Server socket in listen state so that it can wait for client connections
if ( listen( hServerSocket, SOMAXCONN ) == SOCKET_ERROR )
{
cout << "Unable to put server in listen state" << endl ;
// Free the socket and cleanup the environment initialized by WSAStartup()
closesocket( hServerSocket ) ;
WSACleanup( ) ;
return -1 ;
}
// Start the infinite loop
while ( true )
{
// As the socket is in listen mode there is a connection request pending.
// Calling accept( ) will succeed and return the socket for the request.
SOCKET hClientSocket ;
struct sockaddr_in clientAddr ;
int nSize = sizeof( clientAddr ) ;
hClientSocket = accept( hServerSocket, ( struct sockaddr *) &clientAddr, &nSize ) ;
if ( hClientSocket == INVALID_SOCKET )
{
cout << "accept( ) failed" << endl ;
}
else
{
HANDLE hClientThread ;
struct CLIENT_INFO* clientInfo = (struct CLIENT_INFO*) malloc(sizeof(struct CLIENT_INFO)) ;
DWORD dwThreadId ;
clientInfo -> clientAddr = clientAddr ;
clientInfo -> hClientSocket = hClientSocket ;
cout << "Client connected from " << inet_ntoa( clientAddr . sin_addr ) << endl ;
// Start the client thread
hClientThread = CreateThread( NULL, 0,
( LPTHREAD_START_ROUTINE ) ClientThread,
( LPVOID ) &(*clientInfo), 0, &dwThreadId ) ;
if ( hClientThread == NULL )
{
cout << "Unable to create client thread" << endl ;
}
else
{
CloseHandle( hClientThread ) ;
}
}
}
closesocket( hServerSocket ) ;
WSACleanup( ) ;
return 0 ;
}
bool InitWinSock2_0( )
{
WSADATA wsaData ;
WORD wVersion = MAKEWORD( 2, 0 ) ;
if ( ! WSAStartup( wVersion, &wsaData ) )
return true ;
return false ;
}
BOOL WINAPI ClientThread( LPVOID lpData )
{
CLIENT_INFO *pClientInfo = ( CLIENT_INFO * ) lpData ;
char szBuffer[ 1024 ] ;
int nLength ;
while ( 1 )
{
nLength = recv( pClientInfo -> hClientSocket, szBuffer, sizeof( szBuffer ), 0 ) ;
if ( nLength > 0 )
{
szBuffer[ nLength ] = '\0' ;
cout << "Received " << szBuffer << " from " << inet_ntoa( pClientInfo -> clientAddr . sin_addr ) << endl ;
// Convert the string to upper case and send it back, if its not QUIT
strupr( szBuffer ) ;
if ( strcmp( szBuffer, "QUIT" ) == 0 )
{
closesocket( pClientInfo -> hClientSocket ) ;
return TRUE ;
}
// send( ) may not be able to send the complete data in one go.
// So try sending the data in multiple requests
int nCntSend = 0 ;
char *pBuffer = szBuffer ;
while ( ( nCntSend = send( pClientInfo -> hClientSocket, pBuffer, nLength, 0 ) != nLength ) )
{
if ( nCntSend == -1 )
{
cout << "Error sending the data to " << inet_ntoa( pClientInfo -> clientAddr . sin_addr ) << endl ;
break ;
}
if ( nCntSend == nLength )
break ;
pBuffer += nCntSend ;
nLength -= nCntSend ;
}
}
else
{
cout << "Error reading the data from " << inet_ntoa( pClientInfo -> clientAddr . sin_addr ) << endl ;
}
}
return TRUE ;
}
客户:
#include <winsock2.h>
#include <iostream>
using namespace std;
char szServerIPAddr[ 20 ] = "192.168.1.221" ; // Put here the IP address of the server
int nServerPort = 5050 ; // The server port that will be used by // clients to talk with the server
bool InitWinSock2_0( ) ;
int main( )
{
cout << "Enter the server IP Address: " ;
cin >> szServerIPAddr ;
cout << "Enter the server port number: " ;
cin >> nServerPort ;
if ( ! InitWinSock2_0( ) )
{
cout << "Unable to Initialize Windows Socket environment" << WSAGetLastError( ) << endl ;
return -1 ;
}
SOCKET hClientSocket ;
hClientSocket = socket(
AF_INET, // The address family. AF_INET specifies TCP/IP
SOCK_STREAM, // Protocol type. SOCK_STREM specified TCP
0 // Protoco Name. Should be 0 for AF_INET address family
) ;
if ( hClientSocket == INVALID_SOCKET )
{
cout << "Unable to create Server socket" << endl ;
// Cleanup the environment initialized by WSAStartup()
WSACleanup( ) ;
return -1 ;
}
// Create the structure describing various Server parameters
struct sockaddr_in serverAddr ;
serverAddr . sin_family = AF_INET ; // The address family. MUST be AF_INET
serverAddr . sin_addr . s_addr = inet_addr( szServerIPAddr ) ;
serverAddr . sin_port = htons( nServerPort ) ;
// Connect to the server
if ( connect( hClientSocket, ( struct sockaddr * ) &serverAddr, sizeof( serverAddr ) ) < 0 )
{
cout << "Unable to connect to " << szServerIPAddr << " on port " << nServerPort << endl ;
closesocket( hClientSocket ) ;
WSACleanup( ) ;
return -1 ;
}
char szBuffer[ 1024 ] = "" ;
while ( strcmp( szBuffer, "QUIT" ) != 0 )
{
cout << "Enter the string to send (QUIT) to stop: " ;
cin >> szBuffer ;
int nLength = strlen( szBuffer ) ;
// send( ) may not be able to send the complete data in one go.
// So try sending the data in multiple requests
int nCntSend = 0 ;
char *pBuffer = szBuffer ;
while ( ( nCntSend = send( hClientSocket, pBuffer, nLength, 0 ) != nLength ) )
{
if ( nCntSend == -1 )
{
cout << "Error sending the data to server" << endl ;
break ;
}
if ( nCntSend == nLength )
break ;
pBuffer += nCntSend ;
nLength -= nCntSend ;
}
strupr( szBuffer ) ;
if ( strcmp( szBuffer, "QUIT" ) == 0 )
{
break ;
}
nLength = recv( hClientSocket, szBuffer, sizeof( szBuffer ), 0 ) ;
if ( nLength > 0 )
{
szBuffer[ nLength ] = '\0' ;
cout << "Received " << szBuffer << " from server" << endl ;
}
}
closesocket( hClientSocket ) ;
WSACleanup( ) ;
return 0 ;
}
bool InitWinSock2_0( )
{
WSADATA wsaData ;
WORD wVersion = MAKEWORD( 2, 0 ) ;
if ( ! WSAStartup( wVersion, &wsaData ) )
return true ;
return false ;
}
如果您需要进一步的帮助,请实施您的服务器,并在此网站上提出新的、更具体的问题: 首先,创建一个适当的消息队列。旁注:std::vector的缺点是,您总是在插入或删除消息时移动数据,这取决于您如何实现它。某种类型的环形缓冲区效率更高,但它可以基于std::vector实现。 创建另一个包含所有已连接客户端的队列。或者重复使用您的环形缓冲区,使其成为模板,或者,由于更改不太频繁,只需使用std::vector。 创建一个线程,从队列中读取第一条消息并将其发送给列表中的所有客户端。您可以使用让线程在队列为空时完全休眠,并在插入某些数据后立即唤醒。 对于每个接受的连接,创建一个从套接字读取的新线程,并将接受的数据放入队列中。 请注意,您需要保护消息队列和客户机列表不受竞争条件的影响,因为它们都是从多个线程访问的 如何将此echo服务器转换为聊天服务器?通过编写这样做的代码。因此,它既不是代码编写服务,也不是教程服务。你具体的问题是什么?