基於UDP的P2P聊天工具 0 1

2021-08-08 22:17:30 字數 4572 閱讀 8400

簡介:

1)這是乙個windows的p2p聊天工具;

2)它支援區域網內1對1傳送文字訊息;

3)它的介面是dos控制台介面;

1)入門級udp套接字程式設計;

2)udp的connect函式;

3)入門級windows多執行緒;

一、入門級udp套接字程式設計

m_sockfd =socket(pf_inet, sock_dgram, ipproto_udp);

2)指明位址資訊,並繫結位址

sockaddr_in servaddr = ;

servaddr.sin_family = af_inet;

servaddr.sin_addr.s_addr = htonl(inaddr_any);

servaddr.sin_port = htons(port);

bind(m_sockfd, (const sockaddr*)&servaddr, sizeof(servaddr));

3)udp訊息的收發

udp的訊息收發通常使用recvfrom和sendto。但是,由於我們這裡使用另一種方式,所以這裡對這兩個函式不做細說。

二、udp的connect函式和訊息收發

我們知道udp是一種無連線的協議。但是,對於udp套接字,我們仍然可以呼叫connect函式,只是這時的connect與tcp中的connect是不同的:

」在tcp中,connect引發三次握手的過程;而在udp中,它只是檢查是否存在立即克制的錯誤(如乙個顯然不可達的目的地),然後記錄對端的ip位址和埠號「。這句話出自《unix網路程式設計》卷1第三版的8.11節。

給udp套接字呼叫connect有三點好處:

1)由於對端的位址已經被記錄,我們可以使用recv和send進行訊息收發。最直觀的變化就是,recv/send所需要的入參,比recvfrom/sendto少了兩個。

2)當對端不存在時,可以很快知道。

3)效能上獲得提公升。不過,由於這裡只是簡單的1對1字元訊息收發,所以可能感覺不到明顯差異。

// 這裡的servaddr記錄對端的位址

sockaddr_in servaddr = ;

servaddr.sin_family = af_inet;

servaddr.sin_addr.s_addr = inet_addr(ip);

servaddr.sin_port = htons(port);

connect(m_sockfd, (const sockaddr*)&servaddr, sizeof(servaddr));

send(m_sockfd, buf, len, 0);

recv(m_sockfd, buf, len, 0);

三、入門級windows多執行緒

在linux中,標準輸入和套接字同樣可以作為檔案描述符進行處理。所以它可以使用select等,很方便地進行多路復用。

但是,在windows中,標準輸入跟套接字沒法當作一回事進行處理。所以,為了簡單處理,這裡使用多執行緒的方式進行處理。

在主線程中,使用recv進行阻塞式等待接收來自對端的訊息;在子執行緒中,接收標準輸入的訊息,然後傳送給對端。

windows中開執行緒的方式,可以像這樣:

1)首先,定義乙個執行緒函式;2)然後,建立執行緒。

dword winapi threadfunc(lpvoid pparam)

handle

handle

= createthread(null, 0, threadfunc, this, 0, null);

四、**

包含talker.h,talker.cpp,main.cpp,start.bat;

main.cpp

#include 

#include "talker.h"

using

namespace

std;

int main(int argc, char** argv)

else

system("pause");

return

0;}

start.bat(作為使用示例;ps. 注意路徑、ip、埠)

@echo off

ifexist ./talker.exe (

start talker.exe 33333

127.0.0.1

44444

start talker.exe 44444

127.0.0.1

33333

) else (

echo "./talker.exe does not

exist"

pause

)

talker.h

#pragma once

#include

#pragma comment(lib, "ws2_32")

class talker

;

talker.cpp

#include 

#include "talker.h"

using

namespace

std;

// 獲取標準輸入,再傳送給對端;它以執行緒函式的形式被呼叫;

dword winapi threadfunc(lpvoid pparam)

; cin.getline(buf, maxbyte);

((talker*)pparam)->send(buf, strlen(buf) + 1);

}return0;}

// 初始化wsadata,繫結本地埠,建立udp「連線」;

talker::talker(unsigned

short myport, const

char* peerip, unsigned

short peerport)

// 清理wsadata和套接字;

talker::~talker()

// 初始化wsadata;

void talker::init()

}// 套接字繫結本地埠;

void talker::openport(unsigned

short port)

; servaddr.sin_family = af_inet;

servaddr.sin_addr.s_addr = htonl(inaddr_any);

servaddr.sin_port = htons(port);

if ((m_sockfd = socket(pf_inet, sock_dgram, ipproto_udp)) == invalid_socket)

if (bind(m_sockfd, (const sockaddr*)&servaddr, sizeof(servaddr)) != 0)

}// 建立udp「連線」;

void talker::aimat(const

char* ip, unsigned

short port)

; servaddr.sin_family = af_inet;

servaddr.sin_addr.s_addr = inet_addr(ip);

servaddr.sin_port = htons(port);

if (connect(m_sockfd, (const sockaddr*)&servaddr, sizeof(servaddr)) < 0)

}// 建立執行緒,獲取標準輸入,傳送給對端;

// 接收來自對端的訊息,並列印;

void talker::start()

; if (recv(buf, sizeof(buf)) >= 0)

cout

<< "from peer: "

<< buf << endl;

}}int talker::send(const

char* buf, int len)

return0;}

int talker::recv(char * buf, int len)

return

0;}

五、說明

這個**是可以執行的,而且在執行start.bat後生成的兩個黑框也確實是可以相互發訊息的。不過它其實還是有點問題的。這在另一篇裡會進行介紹——基於udp的p2p聊天工具 0.2

C 基於UDP實現的P2P語音聊天工具

語音獲取 要想傳送語音資訊,首先得獲取語音,這裡有幾種方法,一種是使用directx的directxsound來錄音,我為了簡便使用乙個開源的外掛程式naudio來實現語音錄取。在專案中引用naudio.dll 錄音相關 private iw ein w ein private w efilewri...

基於python的簡易區域網聊天工具

threading 多執行緒模組,實現同時接收,同時傳送 本地機器兩個命令視窗不同埠號執行,實際使用可在區域網內電腦執行 接受資訊函式 def rec upd while true 接收訊息,最多為1024位元組 data upd.recvfrom 1024 data為乙個元組,info為資訊內容,...

P2P之UDP穿透的簡單實現方式

full cone nat 內網主機建立乙個udpsocket localip localport 第一次使用這個socket給外部主機傳送資料時nat會給其分配乙個公網 publicip publicport 以後用這個socket向外面任何主機傳送資料都將使用這對 publicip public...