分享一段基於UDP的多線程網絡點對點通信程序。
文件一:CComm.h
#ifndef _CCOMM_H_
#define _CCOMM_H_
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <winsock.h>
#define socklen_t int
#pragma comment(lib, "wsock32.lib")
class CComm
{
private:
static void *ListenThread(void *data);
SOCKET ListenSocket; // 等待接收數據的socket
sockaddr_in srv; // 綁定地址
sockaddr_in client; // 發送數據過來的地址
public:
CComm();
~CComm();
bool SendMsg(char *Msg, int Len, char *host, short port);
bool Listen(int PortNum);
};
#endif // #define _CCOMM_H_
文件一:CComm.cpp
#include "CComm.h"
CComm::CComm()
{
//構造函數
ListenSocket = INVALID_SOCKET; // 開始設置爲INVALID_SOCKET
#ifdef _WIN32 // 如果是win32系統
WORD VersionRequested = MAKEWORD(1,1);
WSADATA wsaData;
WSAStartup(VersionRequested, &wsaData); // 啓動winsock服務
if ( wsaData.wVersion != VersionRequested )
{
printf("Wrong version or WinSock not loaded\n");
fflush(0);
}
#endif
}
//析構函數
CComm::~CComm()
{
if ( ListenSocket != INVALID_SOCKET )
closesocket( ListenSocket ); // 如果已經創建、則關閉
#ifdef _WIN32 // 調用WSACleanup
WSACleanup();
#endif
}
bool CComm::SendMsg( char *Msg, int Len, char *host, short port )
{
signed int Sent;
hostent *hostdata;
if ( atoi(host) ) // 是否IP地址爲標準形式
{
u_long ip = inet_addr( host );
hostdata = gethostbyaddr( (char *)&ip, sizeof(ip), PF_INET );
}
else // 否則則可能是機器名
{
hostdata = gethostbyname( host );
}
if ( !hostdata )
{
printf("獲得機器名錯誤\n");
fflush(0);
return false;
}
sockaddr_in dest; // 發送目標地址
dest.sin_family = PF_INET;
dest.sin_addr = *(in_addr *)(hostdata->h_addr_list[0]);
dest.sin_port = htons( port );
printf("信息已經被髮送到主機 %s 端口爲 %i\n", inet_ntoa(dest.sin_addr), ntohs(dest.sin_port));
//數據發送
Sent = sendto(ListenSocket, Msg, Len, 0, (sockaddr *)&dest, sizeof(sockaddr_in));
if ( Sent != Len )
{
printf("錯誤發送UDP信息\n");
fflush(0);
return false;
}
return true;
}
void *CComm::ListenThread( void *data )
{
char buf[4096];
CComm *Comm = (CComm *)data;
int len = sizeof(Comm->client);
while(1) // 一直循環
{
//接收數據
int result = recvfrom( Comm->ListenSocket, buf, sizeof(buf)-1, 0, (sockaddr *)&Comm->client, (socklen_t *)&len);
if ( result > 0 )
{
buf[result] = 0;
printf("Message received from host %s port %i\n", inet_ntoa(Comm->client.sin_addr), ntohs(Comm->client.sin_port));
printf(">> %s", buf);
fflush(0);
}
}
}
//地址綁定,注意在UDP協議中,不需要listen,這裏函數listen只是綁定一個端口
bool CComm::Listen( int PortNum )
{
ListenSocket = socket(PF_INET, SOCK_DGRAM, 0);
if ( ListenSocket == INVALID_SOCKET )
{
printf("Error: socket創建失敗\n");
fflush(0);
return false;
}
srv.sin_family = PF_INET;
srv.sin_addr.s_addr = htonl( INADDR_ANY ); // 任何地址
srv.sin_port = htons( PortNum );
if ( bind( ListenSocket, (struct sockaddr *)&srv, sizeof(srv)) != 0 )
{
printf("Error: 綁定失敗\n");
fflush(0);
closesocket( ListenSocket );
return false;
}
int ThreadID; // 線程id
DWORD thread;
//調用createthread創建線程
ThreadID = (int)CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(CComm::ListenThread), (void *)this, 0, &thread);
ThreadID = ThreadID ? 0 : 1; // 如果成功,則返回爲0
if(ThreadID) // ThreadID如果不爲0,則線程創建失敗
{
printf("線程創建失敗\n");
return false;
}
else
return true;
}