簡介:
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...