If you are new to network programming, you can refer to following code of mine, it be used for client. If you’re familiar with networking, I recommend to use BSD API or network library(e.g. boost::asio, RakNet), not use FSocket of UE4, especially on server-side.
MyTcpClient.h
FSocket* ClientSock;
bool Connected_;
HRecvThread RecvThread;
MyTcpClient.cpp
void MyTcpClient::Init()
{
if (ClientSock)
{
ClientSock->Close();
ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(ClientSock);
}
ClientSock = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateSocket(NAME_Stream, TEXT("default"), false);
}
bool MyTcpClient::Connect(const char* IP, int Port)
{
if (Connected_)
{
return true;
}
FString address(IP);
int32 port = 3001;
FIPv4Address ip;
FIPv4Address::Parse(address, ip);
TSharedRef<FInternetAddr> addr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr();
addr->SetIp(ip.Value);
addr->SetPort(Port);
RecvThread.Start(ClientSock, this);
Connected_ = ClientSock->Connect(*addr);
return Connected_;
}
bool MyTcpClient::Send(uint8* Data, int Len)
{
if (!ClientSock || !Connected_)
{
return false;
}
//if you send data in multi-thread situation, you need to copy data to a new byte array
uint8* send_buf = Data;
int total_send = 0;
int req_send = Len;
while (total_send < req_send)
{
int32 sentLen = 0;
bool successful = ClientSock->Send(send_buf + total_send, req_send - total_send, sentLen);
if (!successful)
{
UE_LOG(LogTemp, Error, TEXT("[MyTcpClient::Send]send failed!! dataLen=%d, sentLen=%d"), req_send - total_send, sentLen);
return false;
}
total_send += sentLen;
}
return true;
}
void MyTcpClient::Close()
{
RecvThread.Shutdown();
if (ClientSock)
{
ClientSock->Close();
ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(ClientSock);
ClientSock = NULL;
}
Connected_ = false;
}
MyRecvThread.h
class MyRecvThread : public FRunnable
{
public:
MyRecvThread();
~MyRecvThread();
void Start(FSocket* CliSock, MyTcpClient* const TcpCLient);
// Begin FRunnable interface.
//virtual bool Init();
uint32 Run() override;
//virtual void Stop();
//virtual void Exit();
// End FRunnable interface
void Stop();
private:
FRunnableThread* Thread;
FSocket* ClientSocket;
FThreadSafeBool Started;
MyTcpClient* TcpClient;
};
MyRecvThread.cpp
void MyRecvThread::Start(FSocket* CliSock, MyTcpClient* const TcpCLient)
{
Started.AtomicSet(true);
ClientSocket = CliSock;
this->TcpClient = TcpCLient;
Thread = FRunnableThread::Create(this, TEXT("FPrimeNumberWorker"), 0, TPri_BelowNormal);
}
uint32 MyRecvThread::Run()
{
uint8 buf[512];
uint8* recv_buf = buf;
int readLenSeq = 0;
while (Started)
{
uint32 Size;
if (ClientSocket->HasPendingData(Size))
{
int32 bytesRead = 0;
ClientSocket->Recv(recv_buf, readLenSeq, bytesRead);
....
//your code to handle byte array
....
}
FPlatformProcess::Sleep(0.01);
}
if (Thread)
{
delete Thread;
Thread = NULL;
}
return 0;
}
void MyRecvThread::Stop()
{
Started.AtomicSet(false);
}
add Networking Dependency in the constructor of *.Build.cs(e.g. MyProj.Build.cs):
PrivateDependencyModuleNames.AddRange(new string] { "Sockets", "Networking" });