vb 实现内网与公网聊天

dongao8080 2011-04-12 03:47:04
如题。局域网内互聊的可以实现了。
但不能像qq那样的,即通过路由器上网还是直连上网都能连通。
这两天搜了一下,有的说需要公网服务器什么的,有的说需要端口映射的。。。不懂啊。谁能给个详细的解说吗?能给源码更好啊。

ps:我有个小网站,有独立ip什么的。
...全文
1036 34 打赏 收藏 转发到动态 举报
写回复
用AI写文章
34 条回复
切换为时间正序
请发表友善的回复…
发表回复
雾都男孩 2013-10-28
  • 打赏
  • 举报
回复
求一个两个内网机器可以通信又不需要服务器的。。。给个提示也好啊。
cnlm2 2011-04-29
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 supermanking 的回复:]
这就是所谓的P2P技术,如果你了解Sock API的话,应该很好实现该技术,
在网络上有很多 C 实现该技术的范例,在 Linux 论坛里这种已经被看为老掉牙的
技术了,UDP、TCP的P2P代码满天飞,其实原理也很简单,用VB其实也可以实现,
不过很少看见有VB这方面的代码亮相。

我也写过这类程序,不过也是用VC,如果要用VB来写,感觉效率可能不行,因为
虽然VB可以开多线程来处理……
[/Quote]

大概就是这样的吧!
CppCoder 2011-04-29
  • 打赏
  • 举报
回复
经典技术,学习了
dongao8080 2011-04-18
  • 打赏
  • 举报
回复
正在研究中...
dongao8080 2011-04-18
  • 打赏
  • 举报
回复
SupermanKing大哥非常热心!谢谢!
  • 打赏
  • 举报
回复
公网服务器
jiashie 2011-04-16
  • 打赏
  • 举报
回复
端口映射+域名解析 //前提是你能接触到路由器,进行设置
QQ之类的不需要设置也能聊天,估计是用公共服务器中转再建立连接的方式吧
//这个真没做过
现在还是人类 2011-04-16
  • 打赏
  • 举报
回复
[Quote=引用 26 楼 xslslx 的回复:]
SupermanKing大哥的知识很强大,佩服一下下。
看楼主的样子好像是要在企业即将使用的软件中添加一个聊天功能,当然有可能是异地有分公司的企业吧。
我有一个小小的想法,没有时间认证的,哪位大哥证明一下?
我个人感觉局域网和公网好像是一样的运行结构吧,如果A、B两台异地电脑相互通信,A、B两台都有公网IP,那么这两台电脑之间不是就好像局域网的两台电脑通讯了吗?这样A、B能不能直接通讯呢?
……
[/Quote]
这个概念是错误的,因为Internet和内网架构是不一样的,先不说硬件层和硬件层间的通讯模式或
交换机制,就由IP地址开始说起吧,IP地址现在通常使用的是4字节的IP地址,即最多支持256的4次方
个地址,就是所最多支持40多亿个有用自己独立IP的终端在这个大网络环境运作,而世界人口总数在
60多亿人口,单每人一个IP都分配不过来,何况还有无人看管的机房设备需要分配的IP,每个人可能
拥有办公室、家庭、手机上网这类需求,而且介于分配管理上的需求,每个管理部门只有一定配额的
IP段可分配,而还有可能因为地区,网络供应商和使用时间的问题浪费掉部分IP地址某些时段不在
Internet上,所以,在Internet单靠真实的IP量是不能满足与目前的需求的,所以出现了伪IP的概念
和IP6的概念,但IP6目前还没有很普及,我们通常也是在IP4的环境下上网,所以伪IP就和我们接触
得比较多,只是很多人不知道而已。其实如果你注意一下会发现,每次用PPPOE拨号的时候,如果有心
去某个网站看一下,会发现,网站上显示你的IP地址和你拨号显示的IP地址不一样,其实就是电信部门
帮你分配了个伪IP,如果一样,恭喜你,你拥有了真实IP。
伪IP其实是利用 TCP/IP 或 UDP/IP 通讯中的另一个参数配合实现的过程,这就是端口,通常一个内网
在同一个路由环境下能运作是是在同一个网段下的,也就是所最多255个终端,而这255个终端只要配合
路由协议中的端口,基本还是能满足常用的通讯需求的,因为基本上没人会用完所有的端口在一台终端
机来跑,因为这么个弄法,可能没到路由交换层,你的终端机已经出问题了,呵呵。
所以,Internet 的网络环境与内网环境是不一样的,当然,也有别的方法可以将网络环境设置得更为
简单,就比如说VPN,当你连入Internet后,可以通过VPN拨号到你的VPN服务器,通过这个服务器将
所有拨入VPN服务器的Internet终端模拟成一个局域网,这类似于驱动层的过滤驱动,他会把复杂的
网络信息转换成内网方式进行通讯。这样一来,在程序设计上就简单很多。楼主也可以参考这种方式
使用你的程序的,不用改动你原来的程序,只需要架设一台VPN服务器,然后在你的系统中建立个VPN
拨号连接,每次都自动拨号就可以了。这些都是Windows Server 2003系统自带的设置。使用其实很
简单的,你可以考虑考虑。
xslslx 2011-04-15
  • 打赏
  • 举报
回复
SupermanKing大哥的知识很强大,佩服一下下。
看楼主的样子好像是要在企业即将使用的软件中添加一个聊天功能,当然有可能是异地有分公司的企业吧。
我有一个小小的想法,没有时间认证的,哪位大哥证明一下?
我个人感觉局域网和公网好像是一样的运行结构吧,如果A、B两台异地电脑相互通信,A、B两台都有公网IP,那么这两台电脑之间不是就好像局域网的两台电脑通讯了吗?这样A、B能不能直接通讯呢?

  • 打赏
  • 举报
回复
为什么不自己搜一搜
  • 打赏
  • 举报
回复
有介绍过程,点击链接
  • 打赏
  • 举报
回复
有.net源码,点击链接
dongao8080 2011-04-13
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 supermanking 的回复:]
引用 17 楼 dongao8080 的回复:
哈哈,所以我更想学学端口映射了、打洞了什么的。
有人愿辅导我学会并完成这个东西吗?我出人民币100元求助。。

我上面不是说了整个过程吗?只要你按照这种过程处理,肯定行的,
如果要源码你才能开始动手,你可以到网上搜索一下呀,VC p2p源代码
有了原理、操作过程、源代码你如果还弄不了,那就算别人教你也
只是别人写一遍程序给你看而已。不会……
[/Quote]

好人啊...不过你写那些我都看不懂..我也只是初学vb,不懂vc啊.
"然后设置好基本的参数绑定套接字就可以开启线程狂读数据了"..看得我挺激动的就是不知道啥意思.

顺便描述一下:这个功能是要嵌进公司一个软件中去的..并且这个软件其它功能已差不多ok了,就这个在线沟通的还没做出来.所以这个时候要换用vc来做会头大的.而我现在更想直接得到个代码,或者控件.我对vb了解本不多哈,更别说用vb来实现什么通信协议,等我学会了公司就要扣我money了.因为当时我试了局域网沟通很成功后对boss说了没问题的.
现在还是人类 2011-04-13
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 dongao8080 的回复:]
哈哈,所以我更想学学端口映射了、打洞了什么的。
有人愿辅导我学会并完成这个东西吗?我出人民币100元求助。。
[/Quote]
我上面不是说了整个过程吗?只要你按照这种过程处理,肯定行的,
如果要源码你才能开始动手,你可以到网上搜索一下呀,VC p2p源代码
有了原理、操作过程、源代码你如果还弄不了,那就算别人教你也
只是别人写一遍程序给你看而已。不会有太大区别。因为如果不能
通过原理、操作过程、源代码这些资源自己弄懂,只能是基础差太
远,即使别人教也不可能一步登天的取得成果。只有自己把基础打
牢才是问题的解决方法。否则和直接用现成的工具没什么两样。
dongao8080 2011-04-13
  • 打赏
  • 举报
回复
哈哈,所以我更想学学端口映射了、打洞了什么的。
有人愿辅导我学会并完成这个东西吗?我出人民币100元求助。。
现在还是人类 2011-04-13
  • 打赏
  • 举报
回复
这是客户端的主要过程

#pragma comment(lib,"ws2_32.lib")

#include "windows.h"
#include "..\proto.h"
#include "..\Exception.h"
#include <iostream>
using namespace std;

UserList ClientList;

#define COMMANDMAXC 256
#define MAXRETRY 5

SOCKET PrimaryUDP;
char UserName[10];
char ServerIP[20];

bool RecvedACK;

void InitWinSock()
{
WSADATA wsaData;

if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
printf("Windows sockets 2.2 startup");
throw Exception("");
}
else{
printf("Using %s (Status: %s)\n",
wsaData.szDescription, wsaData.szSystemStatus);
printf("with API versions %d.%d to %d.%d\n\n",
LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion),
LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion));
}
}

SOCKET mksock(int type)
{
SOCKET sock = socket(AF_INET, type, 0);
if (sock < 0)
{
printf("create socket error");
throw Exception("");
}
return sock;
}

stUserListNode GetUser(char *username)
{
for(UserList::iterator UserIterator=ClientList.begin();
UserIterator!=ClientList.end();
++UserIterator)
{
if( strcmp( ((*UserIterator)->userName), username) == 0 )
return *(*UserIterator);
}
throw Exception("not find this user");
}

void BindSock(SOCKET sock)
{
sockaddr_in sin;
sin.sin_addr.S_un.S_addr = INADDR_ANY;
sin.sin_family = AF_INET;
sin.sin_port = 0;

if (bind(sock, (struct sockaddr*)&sin, sizeof(sin)) < 0)
throw Exception("bind error");
}

void ConnectToServer(SOCKET sock,char *username, char *serverip)
{
sockaddr_in remote;
remote.sin_addr.S_un.S_addr = inet_addr(serverip);
remote.sin_family = AF_INET;
remote.sin_port = htons(SERVER_PORT);

stMessage sendbuf;
sendbuf.iMessageType = LOGIN;
strncpy(sendbuf.message.loginmember.userName, username, 10);

sendto(sock, (const char*)&sendbuf, sizeof(sendbuf), 0, (const sockaddr*)&remote,sizeof(remote));

int usercount;
int fromlen = sizeof(remote);
int iread = recvfrom(sock, (char *)&usercount, sizeof(int), 0, (sockaddr *)&remote, &fromlen);
if(iread<=0)
{
throw Exception("Login error\n");
}

cout<<"Have "<<usercount<<" users logined server:"<<endl;
for(int i = 0;i<usercount;i++)
{
stUserListNode *node = new stUserListNode;
recvfrom(sock, (char*)node, sizeof(stUserListNode), 0, (sockaddr *)&remote, &fromlen);
ClientList.push_back(node);
cout<<"Username:"<<node->userName<<endl;
in_addr tmp;
tmp.S_un.S_addr = htonl(node->ip);
cout<<"UserIP:"<<inet_ntoa(tmp)<<endl;
cout<<"UserPort:"<<node->port<<endl;
cout<<""<<endl;
}
}

void OutputUsage()
{
cout<<"You can input you command:\n"
<<"Command Type:\"send\",\"exit\",\"getu\"\n"
<<"Example : send Username Message\n"
<<" exit\n"
<<" getu\n"
<<endl;
}

bool SendMessageTo(char *UserName, char *Message)
{
char realmessage[256];
unsigned int UserIP;
unsigned short UserPort;
bool FindUser = false;
for(UserList::iterator UserIterator=ClientList.begin();
UserIterator!=ClientList.end();
++UserIterator)
{
if( strcmp( ((*UserIterator)->userName), UserName) == 0 )
{
UserIP = (*UserIterator)->ip;
UserPort = (*UserIterator)->port;
FindUser = true;
}
}

if(!FindUser)
return false;

strcpy(realmessage, Message);
for(int i=0;i<MAXRETRY;i++)
{
RecvedACK = false;

sockaddr_in remote;
remote.sin_addr.S_un.S_addr = htonl(UserIP);
remote.sin_family = AF_INET;
remote.sin_port = htons(UserPort);
stP2PMessage MessageHead;
MessageHead.iMessageType = P2PMESSAGE;
MessageHead.iStringLen = (int)strlen(realmessage)+1;
int isend = sendto(PrimaryUDP, (const char *)&MessageHead, sizeof(MessageHead), 0, (const sockaddr*)&remote, sizeof(remote));
isend = sendto(PrimaryUDP, (const char *)&realmessage, MessageHead.iStringLen, 0, (const sockaddr*)&remote, sizeof(remote));

for(int j=0;j<10;j++)
{
if(RecvedACK)
return true;
else
Sleep(300);
}

sockaddr_in server;
server.sin_addr.S_un.S_addr = inet_addr(ServerIP);
server.sin_family = AF_INET;
server.sin_port = htons(SERVER_PORT);

stMessage transMessage;
transMessage.iMessageType = P2PTRANS;
strcpy(transMessage.message.translatemessage.userName, UserName);

sendto(PrimaryUDP, (const char*)&transMessage, sizeof(transMessage), 0, (const sockaddr*)&server, sizeof(server));
Sleep(100);
}
return false;
}

void ParseCommand(char * CommandLine)
{
if(strlen(CommandLine)<4)
return;
char Command[10];
strncpy(Command, CommandLine, 4);
Command[4]='\0';

if(strcmp(Command,"exit")==0)
{
stMessage sendbuf;
sendbuf.iMessageType = LOGOUT;
strncpy(sendbuf.message.logoutmember.userName, UserName, 10);
sockaddr_in server;
server.sin_addr.S_un.S_addr = inet_addr(ServerIP);
server.sin_family = AF_INET;
server.sin_port = htons(SERVER_PORT);

sendto(PrimaryUDP,(const char*)&sendbuf, sizeof(sendbuf), 0, (const sockaddr *)&server, sizeof(server));
shutdown(PrimaryUDP, 2);
closesocket(PrimaryUDP);
exit(0);
}
else if(strcmp(Command,"send")==0)
{
char sendname[20];
char message[COMMANDMAXC];
int i;
for(i=5;;i++)
{
if(CommandLine[i]!=' ')
sendname[i-5]=CommandLine[i];
else
{
sendname[i-5]='\0';
break;
}
}
strcpy(message, &(CommandLine[i+1]));
if(SendMessageTo(sendname, message))
printf("Send OK!\n");
else
printf("Send Failure!\n");
}
else if(strcmp(Command,"getu")==0)
{
int command = GETALLUSER;
sockaddr_in server;
server.sin_addr.S_un.S_addr = inet_addr(ServerIP);
server.sin_family = AF_INET;
server.sin_port = htons(SERVER_PORT);

sendto(PrimaryUDP,(const char*)&command, sizeof(command), 0, (const sockaddr *)&server, sizeof(server));
}
}

DWORD WINAPI RecvThreadProc(LPVOID lpParameter)
{
sockaddr_in remote;
int sinlen = sizeof(remote);
stP2PMessage recvbuf;
for(;;)
{
int iread = recvfrom(PrimaryUDP, (char *)&recvbuf, sizeof(recvbuf), 0, (sockaddr *)&remote, &sinlen);
if(iread<=0)
{
printf("recv error\n");
continue;
}
switch(recvbuf.iMessageType)
{
case P2PMESSAGE:
{
char *comemessage= new char[recvbuf.iStringLen];
int iread1 = recvfrom(PrimaryUDP, comemessage, 256, 0, (sockaddr *)&remote, &sinlen);
comemessage[iread1-1] = '\0';
if(iread1<=0)
throw Exception("Recv Message Error\n");
else
{
printf("Recv a Message:%s\n",comemessage);

stP2PMessage sendbuf;
sendbuf.iMessageType = P2PMESSAGEACK;
sendto(PrimaryUDP, (const char*)&sendbuf, sizeof(sendbuf), 0, (const sockaddr*)&remote, sizeof(remote));
}

delete []comemessage;
break;

}
case P2PSOMEONEWANTTOCALLYOU:
{
printf("Recv p2someonewanttocallyou data\n");
sockaddr_in remote;
remote.sin_addr.S_un.S_addr = htonl(recvbuf.iStringLen);
remote.sin_family = AF_INET;
remote.sin_port = htons(recvbuf.Port);

stP2PMessage message;
message.iMessageType = P2PTRASH;
sendto(PrimaryUDP, (const char *)&message, sizeof(message), 0, (const sockaddr*)&remote, sizeof(remote));

break;
}
case P2PMESSAGEACK:
{
RecvedACK = true;
break;
}
case P2PTRASH:
{
printf("Recv p2ptrash data\n");
break;
}
case GETALLUSER:
{
int usercount;
int fromlen = sizeof(remote);
int iread = recvfrom(PrimaryUDP, (char *)&usercount, sizeof(int), 0, (sockaddr *)&remote, &fromlen);
if(iread<=0)
{
throw Exception("Login error\n");
}

ClientList.clear();

cout<<"Have "<<usercount<<" users logined server:"<<endl;
for(int i = 0;i<usercount;i++)
{
stUserListNode *node = new stUserListNode;
recvfrom(PrimaryUDP, (char*)node, sizeof(stUserListNode), 0, (sockaddr *)&remote, &fromlen);
ClientList.push_back(node);
cout<<"Username:"<<node->userName<<endl;
in_addr tmp;
tmp.S_un.S_addr = htonl(node->ip);
cout<<"UserIP:"<<inet_ntoa(tmp)<<endl;
cout<<"UserPort:"<<node->port<<endl;
cout<<""<<endl;
}
break;
}
}
}
}


int main(int argc, char* argv[])
{
try
{
InitWinSock();

PrimaryUDP = mksock(SOCK_DGRAM);
BindSock(PrimaryUDP);

cout<<"Please input server ip:";
cin>>ServerIP;

cout<<"Please input your name:";
cin>>UserName;

ConnectToServer(PrimaryUDP, UserName, ServerIP);

HANDLE threadhandle = CreateThread(NULL, 0, RecvThreadProc, NULL, NULL, NULL);
CloseHandle(threadhandle);
OutputUsage();

for(;;)
{
char Command[COMMANDMAXC];
gets(Command);
ParseCommand(Command);
}
}
catch(Exception &e)
{
printf(e.GetMessage());
return 1;
}
return 0;
}
现在还是人类 2011-04-13
  • 打赏
  • 举报
回复
这是一个P2P的VC范例代码,是个控制台程序。
以下是服务器端的主要过程

#pragma comment(lib, "ws2_32.lib")

#include "windows.h"
#include "..\proto.h"
#include "..\Exception.h"

UserList ClientList;

void InitWinSock()
{
WSADATA wsaData;

if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
printf("Windows sockets 2.2 startup");
throw Exception("");
}
else{
printf("Using %s (Status: %s)\n",
wsaData.szDescription, wsaData.szSystemStatus);
printf("with API versions %d.%d to %d.%d\n\n",
LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion),
LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion));

}
}

SOCKET mksock(int type)
{
SOCKET sock = socket(AF_INET, type, 0);
if (sock < 0)
{
printf("create socket error");
throw Exception("");
}
return sock;
}

stUserListNode GetUser(char *username)
{
for(UserList::iterator UserIterator=ClientList.begin();
UserIterator!=ClientList.end();
++UserIterator)
{
if( strcmp( ((*UserIterator)->userName), username) == 0 )
return *(*UserIterator);
}
throw Exception("not find this user");
}

int main(int argc, char* argv[])
{
try{
InitWinSock();

SOCKET PrimaryUDP;
PrimaryUDP = mksock(SOCK_DGRAM);

sockaddr_in local;
local.sin_family=AF_INET;
local.sin_port= htons(SERVER_PORT);
local.sin_addr.s_addr = htonl(INADDR_ANY);
int nResult=bind(PrimaryUDP,(sockaddr*)&local,sizeof(sockaddr));
if(nResult==SOCKET_ERROR)
throw Exception("bind error");

sockaddr_in sender;
stMessage recvbuf;
memset(&recvbuf,0,sizeof(stMessage));

for(;;)
{
int dwSender = sizeof(sender);
int ret = recvfrom(PrimaryUDP, (char *)&recvbuf, sizeof(stMessage), 0, (sockaddr *)&sender, &dwSender);
if(ret <= 0)
{
printf("recv error");
continue;
}
else
{
int messageType = recvbuf.iMessageType;
switch(messageType){
case LOGIN:
{
// 将这个用户的信息记录到用户列表中
printf("has a user login : %s\n", recvbuf.message.loginmember.userName);
stUserListNode *currentuser = new stUserListNode();
strcpy(currentuser->userName, recvbuf.message.loginmember.userName);
currentuser->ip = ntohl(sender.sin_addr.S_un.S_addr);
currentuser->port = ntohs(sender.sin_port);

ClientList.push_back(currentuser);

// 发送已经登陆的客户信息
int nodecount = (int)ClientList.size();
sendto(PrimaryUDP, (const char*)&nodecount, sizeof(int), 0, (const sockaddr*)&sender, sizeof(sender));
for(UserList::iterator UserIterator=ClientList.begin();
UserIterator!=ClientList.end();
++UserIterator)
{
sendto(PrimaryUDP, (const char*)(*UserIterator), sizeof(stUserListNode), 0, (const sockaddr*)&sender, sizeof(sender));
}

break;
}
case LOGOUT:
{
// 将此客户信息删除
printf("has a user logout : %s\n", recvbuf.message.logoutmember.userName);
UserList::iterator removeiterator = NULL;
for(UserList::iterator UserIterator=ClientList.begin();
UserIterator!=ClientList.end();
++UserIterator)
{
if( strcmp( ((*UserIterator)->userName), recvbuf.message.logoutmember.userName) == 0 )
{
removeiterator = UserIterator;
break;
}
}
if(removeiterator != NULL)
ClientList.remove(*removeiterator);
break;
}
case P2PTRANS:
{
// 某个客户希望服务端向另外一个客户发送一个打洞消息
printf("%s wants to p2p %s\n",inet_ntoa(sender.sin_addr),recvbuf.message.translatemessage.userName);
stUserListNode node = GetUser(recvbuf.message.translatemessage.userName);
sockaddr_in remote;
remote.sin_family=AF_INET;
remote.sin_port= htons(node.port);
remote.sin_addr.s_addr = htonl(node.ip);

in_addr tmp;
tmp.S_un.S_addr = htonl(node.ip);
printf("the address is %s,and port is %d\n",inet_ntoa(tmp), node.port);

stP2PMessage transMessage;
transMessage.iMessageType = P2PSOMEONEWANTTOCALLYOU;
transMessage.iStringLen = ntohl(sender.sin_addr.S_un.S_addr);
transMessage.Port = ntohs(sender.sin_port);

sendto(PrimaryUDP,(const char*)&transMessage, sizeof(transMessage), 0, (const sockaddr *)&remote, sizeof(remote));

break;
}

case GETALLUSER:
{
int command = GETALLUSER;
sendto(PrimaryUDP, (const char*)&command, sizeof(int), 0, (const sockaddr*)&sender, sizeof(sender));

int nodecount = (int)ClientList.size();
sendto(PrimaryUDP, (const char*)&nodecount, sizeof(int), 0, (const sockaddr*)&sender, sizeof(sender));

for(UserList::iterator UserIterator=ClientList.begin();
UserIterator!=ClientList.end();
++UserIterator)
{
sendto(PrimaryUDP, (const char*)(*UserIterator), sizeof(stUserListNode), 0, (const sockaddr*)&sender, sizeof(sender));
}
break;
}
}
}
}

}
catch(Exception &e)
{
printf(e.GetMessage());
return 1;
}

return 0;
}
现在还是人类 2011-04-13
  • 打赏
  • 举报
回复
不过你想要现成的接口,我记得好像是零几年的时候,深圳的一家公司
出了一款P2P控件,支持多种语言调用,包括VB,不过要收点费用。好像
也不是很贵,你应该能接受的,你可以搜索一下 P2P控件
现在还是人类 2011-04-12
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 dongao8080 的回复:]
我有个想法,是通过写入数据库,然后根据用户名来判断信息的来源与去向。并用timer来实时检测数据库中是否有发给自己的信息。有的话就读过来。。

但这样会不会太耗数据库了哈
[/Quote]
你这样还不如直接在IE上定时刷论坛里的某个帖子还简单点,全现成的,包括NT服务都不用考虑,呵呵。
再懒一点的话,直接用QQ更简单。因为这种程序说白了开发已经没多大意义了,练手倒是不错。
  • 打赏
  • 举报
回复
等你客户端多了,网页应付不过来,再用专门的服务器,那就用12楼的技术好了。不过想用vb实现p2p穿透,提高一下是可以的,似乎网上有源码。
加载更多回复(13)

7,763

社区成员

发帖
与我相关
我的任务
社区描述
VB 基础类
社区管理员
  • VB基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧