用vc.net做的一个聊天程序,tcp的
这是SocketServer.h//服务端
using namespace System;
using namespace System::Net;
using namespace System::Net::Sockets;
using namespace System::Threading; // 程序中要创建线程
ref class SocketServer
{
private:
array<Socket^>^ mySocket; // 与客户端会话的socket
Socket^ listenerSocket; // 用于监听的socket
array<bool>^ IsRun; // 服务端的运行状态
array<Thread^>^ myThread; // 监听接收数据的一组线程
Thread^ listenThread; // 监听客户端连接的线程
int MAXNUM_CONNECTION; // 定义最大连接数
String^ localIPStr; // 本地主机的IP地址
unsigned short localPort; // 本地主机的端口号
public:
SocketServer(String^ ServerIP,unsigned short ServerPort,int MaxConnNum)
{
localIPStr=ServerIP;
localPort=ServerPort;
MAXNUM_CONNECTION=MaxConnNum;
myThread=gcnew array<Thread^>(MAXNUM_CONNECTION);
mySocket=gcnew array<Socket^>(MAXNUM_CONNECTION);
IsRun=gcnew array<bool>(MAXNUM_CONNECTION);
// create the socket
listenerSocket = gcnew Socket( AddressFamily::InterNetwork,
SocketType::Stream,
ProtocolType::Tcp );
// bind the listening socket to the port
IPAddress^ localIP=IPAddress::Parse(localIPStr);
EndPoint^ EPhost=gcnew IPEndPoint(localIP,localPort);
listenerSocket->Bind( EPhost );
listenerSocket->Listen(0); // 开始监听
listenThread=gcnew
Thread(gcnew ThreadStart(this,&SocketServer::Listen));
listenThread->Start();//启动监听连接的线程
}
// 循环监听连接,如果有连接则创建会话的socket和接收数据的线程
void Listen()
{
while(true)
{
for(int i=0;i<MAXNUM_CONNECTION;i++)
{
if(!IsRun[i])// 某个编号的线程还没有创建或已终止,则可以创建该线程
{
mySocket[i]=listenerSocket->Accept(); // 接受tcp连接请求
IPEndPoint^ remoteEP=(IPEndPoint^)(mySocket[i]->RemoteEndPoint); // 获得远程IP终端,必须强制转换为IPEndPoint^后才能得到IP和Port
String^ remoteHostInfo=L"接受来自【"+remoteEP->Address->ToString()+":"+remoteEP->Port.ToString()+"】的连接请求!";
Console::WriteLine(remoteHostInfo);
IsRun[i]=true;
ParameterizedThreadStart^ threadStart=gcnew ParameterizedThreadStart(this,&SocketServer::RecvData);
myThread[i]=gcnew Thread(threadStart);
myThread[i]->Start(i);//启动线程,并给线程传递一个参数
}
}
}
}
// 接收数据,ind表示某个线程号(0——MAXNUM_CONNECTION-1)
Void RecvData(Object^ ind) // 注意使用委托ParameterizedThreadStart定义线程时,函数RecvData的参数必须是Object^类型的。这里如果参数ind若定义为int则错误。
{
int index=Convert::ToInt32(ind); // 类型转换
array<Byte>^ bytesRecv = gcnew array<Byte>(1024);
String^ dataStr=String::Empty; // 接收数据的字符创表示
int bytes=0; // 接收到的数据的字节数
array<String^>^ tokens;
String^ remoteHostInfo;
while(true)//Socket处于可读状态则一直循环
{
try
{
bytes=mySocket[index]->Receive(bytesRecv); // 接收数据
this->DisplayPendingByteCount(mySocket[index]);
}
catch(SocketException^ ex)
{
Console::WriteLine("----"+ex->Message+"----");
break;
}
dataStr=System::Text::Encoding::UTF8->GetString(bytesRecv,0,bytes);
//String^ spt="|";
//tokens=dataStr->Trim()->Split(spt->ToCharArray());
IPEndPoint^ localEP=(IPEndPoint^)(mySocket[index]->LocalEndPoint); // 获得本地IP终端,必须强制转换为IPEndPoint^后才能得到IP和Port
IPEndPoint^ remoteEP=(IPEndPoint^)(mySocket[index]->RemoteEndPoint); // 获得远程IP终端,必须强制转换为IPEndPoint^后才能得到IP和Port
remoteHostInfo=L"本地端口【"+localEP->Port.ToString()+"】获得来自["+remoteEP->Address->ToString()+":"+remoteEP->Port.ToString()+"]的消息:"+ dataStr;
Console::WriteLine(remoteHostInfo);
分析接收到的数据(含控制码Chat、Exit等),可自己定义更多一些
//if(tokens[0]=="Chat")
//{
// Console::WriteLine(remoteHostInfo);
//}
//else if(tokens[0]=="Exit")
//{
// IsRun[index]=false;
// Console::WriteLine(remoteHostInfo);
// mySocket[index]->Shutdown(Sockets::SocketShutdown::Both); // 禁止发送和接收
// mySocket[index]->Close(); // 关闭mySocket连接并释放资源
//}
// 转发某个客户端的信息给所有其他客户端
array<Byte>^ msg=System::Text::Encoding::UTF8->GetBytes(remoteHostInfo);
for(int i=0;i<MAXNUM_CONNECTION;i++)// 发消息给所有客户端
{
if(i!=index)
{
if(IsRun[i])
mySocket[i]->Send(msg);
}
}
}
// 关闭与客户端的连接
IPEndPoint^ remoteEP=(IPEndPoint^)(mySocket[index]->RemoteEndPoint); // 获得远程IP终端,必须强制转换为IPEndPoint^后才能得到IP和Port
remoteHostInfo=L"与远程主机["+remoteEP->Address->ToString()+":"+remoteEP->Port.ToString()+"]断开连接!";
Console::WriteLine(remoteHostInfo);
IsRun[index]=false;
mySocket[index]->Shutdown(Sockets::SocketShutdown::Both); // 禁止发送和接收
mySocket[index]->Close(); // 关闭mySocket连接并释放资源
// 结束对应的线程
this->myThread[index]->Abort();
this->IsRun[index]=false; // 修改对应标记
}
void DisplayPendingByteCount( Socket^ s )
{
array<Byte>^ outValue = BitConverter::GetBytes( 0 );
// Check how many bytes have been received.
s->IOControl( IOControlCode::DataToRead, nullptr, outValue );
UInt32 bytesAvailable = BitConverter::ToUInt32( outValue, 0 );
Console::Write( "server has {0} bytes pending,",
bytesAvailable );
Console::WriteLine( "Available property says {0}.",
s->Available );
return;
}
};
// SocketServer.cpp: 主项目文件。
// CreatesSocket.cpp: 主项目文件。
//下面的代码示例会创建套接字,连接到服务器并使用 Poll 检查套接字的状态。
#include "stdafx.h"
#include "SocketServer.h"
using namespace System;
int main(array<System::String ^> ^args)
{
String^ localIPStr=Dns::GetHostByName(Dns::GetHostName())->AddressList[0]->ToString();//"127.0.0.1"; // 本地主机的IP地址
unsigned short localPort=1002; // 本地主机的端口号
const int maxConnectNum=10; //最大连接数
SocketServer^ Server;
Server=gcnew SocketServer(localIPStr,localPort,maxConnectNum);
Console::WriteLine("服务器已就绪,正在监听客户端的连接请求...");
return 0;
}
以下是客户端,在自己机子上实验的,所以ip是一个
// CreatesSocket.cpp: 主项目文件。
//下面的代码示例会创建套接字,连接到服务器并使用 Poll 检查套接字的状态。
#include "stdafx.h"
using namespace System;
using namespace System::Net;
using namespace System::Net::Sockets;
int main(array<System::String ^> ^args)
{
//Creates the Socket for sending data over TCP.
Socket^ s = gcnew Socket( AddressFamily::InterNetwork,
SocketType::Stream,
ProtocolType::Tcp );
String^ remoteIPStr="127.0.0.1"; // 远程主机的IP地址
unsigned short remotePort=1002; // 远程主机的端口号
//IPAddress^ remoteIP=IPAddress::Parse(remoteIPStr);
IPAddress^ remoteIP=Dns::GetHostByName(Dns::GetHostName())->AddressList[0]; // 远程主机的IP地址
EndPoint^ EPhost=gcnew IPEndPoint(remoteIP,remotePort);
// Connects to host using IPEndPoint.
s->Connect( EPhost );
if ( !s->Connected )
{
Console::WriteLine("Unable to connect to host");
}
// Use the SelectWrite enumeration to obtain Socket status.
if ( s->Poll( -1, SelectMode::SelectWrite ) )
{
Console::WriteLine( "This Socket is writable." );
String^ msgStr="大家好才是真的好!";
while(true)
{
if(s->Connected==false)
{
Console::WriteLine( "与服务器的连接已经关闭!" );
break;
}
Console::Write("请输入要发送的消息:");
msgStr=Console::ReadLine();
if(msgStr=="Quit")
break;
array<Byte>^ msg=System::Text::Encoding::UTF8->GetBytes(msgStr);
try
{
s->Send(msg);
}
catch(Exception^ ex)
{
Console::WriteLine( "发送失败!" );
if(s->Connected==false)
{
Console::WriteLine( "与服务器的连接已经关闭!" );
break;
}
}
}
}
else if ( s->Poll( -1, SelectMode::SelectRead ) )
{
Console::WriteLine( "This Socket is readable." );
}
else if ( s->Poll( -1, SelectMode::SelectError ) )
{
Console::WriteLine("This Socket has an error.");
}
s->Close();// 关闭socket连接并释放资源
Console::ReadLine();
return 0;
}