❶ socket通信原理
socket通信原理是一种“打开—读/写—关闭”模式的实现,服务器和客户端各自维护一个“文件”,在建立连接打开后,可以向文件写入内容供对方读取或者读取对方内容,通讯结束时关闭文件。
Socket在应用层和传输层之间的一个抽象层,它把 TCP/IP 层复杂的操作抽象为几个简单的接口,供应用层调用实现进程在网络中的通信。Socket 起源于 UNIX,在 UNIX 一切皆文件的思想下,进程间通信就被冠名为文件描述符(file descriptor)。
Socket 保证了不同计算机之间的通信,也就是网络通信。对于网站,通信模型是服务器与客户端之间的通信。两端都建立了一个 Socket 对象,然后通过 Socket 对象对数据进行传输。通常服务器处于一个无限循环,等待客户端的连接。
(1)网络游戏设计中socket之间数据共享扩展阅读
SOCK_STREAM类型的套接口为全双向的字节流。对于流类套接口,在接收或发送数据前必需处于已连接状态。用connect()调用建立与另一套接口的连接,连接成功后,即可用send()和recv()传送数据。当会话结束后,调用closesocket()。带外数据根据规定用send()和recv()来接收。
实现SOCK_STREAM类型套接口的通讯协议保证数据不会丢失也不会重复。如果终端协议有缓冲区空间,且数据不能在一定时间成功发送,则认为连接中断,其后续的调用也将以WSAETIMEOUT错误返回。
SOCK_DGRAM类型套接口允许使用sendto()和recvfrom()从任意端口发送或接收数据报。如果这样一个套接口用connect()与一个指定端口连接,则可用send()和recv()与该端口进行数据报的发送与接收。
❷ 诛仙游戏跨服服务器是怎么实现数据互通的
至于如何实现多台服务器之间的信息共享,有很多方法可以实现。
一般情况下比如我们设计一个后端服务,包括多个服务器:数据库服务器,web服务器,文件服务器、缓存服务器等的通信,一般是通过socket来设计专门的通信协议,因为比较高效。比如MySQL,MSSQL等也都是有知名的专用端口号。这个场景大多是在一个内网中,所以通信效率一般没问题。
诛梦仙缘,天涯路远,唯有情深不负。完美世界游戏旗下经典仙侠网游《诛仙3》全新版本“情海洄梦”现已倾情上线!空桑山又起劫难,各路豪杰齐进发,再回相遇之地重温旧梦;新人物传揭开小白前尘故事;还有新奇遇等,超多活动内容!我们期待在诛仙与你相逢。
❸ C语言socket编程怎么实现2个客户端之间通信
网络的Socket数据传输是一种特殊的I/O,Socket也是一种文件描述符。Socket也具有一个类似于打开文件的函数调用Socket(),该函数返回一个整型的Socket描述符,随后的连接建立、数据传输等操作都是通过该Socket实现的。
下面用Socket实现一个windows下的c语言socket通信例子,这里我们客户端传递一个字符串,服务器端进行接收。
【服务器端】
#include"stdafx.h"
#include<stdio.h>
#include<winsock2.h>
#include<winsock2.h>
#defineSERVER_PORT5208//侦听端口
voidmain()
{
WORDwVersionRequested;
WSADATAwsaData;
intret,nLeft,length;
SOCKETsListen,sServer;//侦听套接字,连接套接字
structsockaddr_insaServer,saClient;//地址信息
char*ptr;//用于遍历信息的指针
//WinSock初始化
wVersionRequested=MAKEWORD(2,2);//希望使用的WinSockDLL的版本
ret=WSAStartup(wVersionRequested,&wsaData);
if(ret!=0)
{
printf("WSAStartup()failed! ");
return;
}
//创建Socket,使用TCP协议
sListen=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(sListen==INVALID_SOCKET)
{
WSACleanup();
printf("socket()faild! ");
return;
}
//构建本地地址信息
saServer.sin_family=AF_INET;//地址家族
saServer.sin_port=htons(SERVER_PORT);//注意转化为网络字节序
saServer.sin_addr.S_un.S_addr=htonl(INADDR_ANY);//使用INADDR_ANY指示任意地址
//绑定
ret=bind(sListen,(structsockaddr*)&saServer,sizeof(saServer));
if(ret==SOCKET_ERROR)
{
printf("bind()faild!code:%d ",WSAGetLastError());
closesocket(sListen);//关闭套接字
WSACleanup();
return;
}
//侦听连接请求
ret=listen(sListen,5);
if(ret==SOCKET_ERROR)
{
printf("listen()faild!code:%d ",WSAGetLastError());
closesocket(sListen);//关闭套接字
return;
}
printf("Waitingforclientconnecting! ");
printf("Tips:Ctrl+ctoquit! ");
//阻塞等待接受客户端连接
while(1)//循环监听客户端,永远不停止,所以,在本项目中,我们没有心跳包。
{
length=sizeof(saClient);
sServer=accept(sListen,(structsockaddr*)&saClient,&length);
if(sServer==INVALID_SOCKET)
{
printf("accept()faild!code:%d ",WSAGetLastError());
closesocket(sListen);//关闭套接字
WSACleanup();
return;
}
charreceiveMessage[5000];
nLeft=sizeof(receiveMessage);
ptr=(char*)&receiveMessage;
while(nLeft>0)
{
//接收数据
ret=recv(sServer,ptr,5000,0);
if(ret==SOCKET_ERROR)
{
printf("recv()failed! ");
return;
}
if(ret==0)//客户端已经关闭连接
{
printf("Clienthasclosedtheconnection ");
break;
}
nLeft-=ret;
ptr+=ret;
}
printf("receivemessage:%s ",receiveMessage);//打印我们接收到的消息。
}
//closesocket(sListen);
//closesocket(sServer);
//WSACleanup();
}
【客户端】
#include"stdafx.h"
#include<stdio.h>
#include<stdlib.h>
#include<winsock2.h>
#defineSERVER_PORT5208//侦听端口
voidmain()
{
WORDwVersionRequested;
WSADATAwsaData;
intret;
SOCKETsClient;//连接套接字
structsockaddr_insaServer;//地址信息
char*ptr;
BOOLfSuccess=TRUE;
//WinSock初始化
wVersionRequested=MAKEWORD(2,2);//希望使用的WinSockDLL的版本
ret=WSAStartup(wVersionRequested,&wsaData);
if(ret!=0)
{
printf("WSAStartup()failed! ");
return;
}
//确认WinSockDLL支持版本2.2
if(LOBYTE(wsaData.wVersion)!=2||HIBYTE(wsaData.wVersion)!=2)
{
WSACleanup();
printf("InvalidWinSockversion! ");
return;
}
//创建Socket,使用TCP协议
sClient=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(sClient==INVALID_SOCKET)
{
WSACleanup();
printf("socket()failed! ");
return;
}
//构建服务器地址信息
saServer.sin_family=AF_INET;//地址家族
saServer.sin_port=htons(SERVER_PORT);//注意转化为网络节序
saServer.sin_addr.S_un.S_addr=inet_addr("192.168.1.127");
//连接服务器
ret=connect(sClient,(structsockaddr*)&saServer,sizeof(saServer));
if(ret==SOCKET_ERROR)
{
printf("connect()failed! ");
closesocket(sClient);//关闭套接字
WSACleanup();
return;
}
charsendMessage[]="hellothisisclientmessage!";
ret=send(sClient,(char*)&sendMessage,sizeof(sendMessage),0);
if(ret==SOCKET_ERROR)
{
printf("send()failed! ");
}
else
printf("clientinfohasbeensent!");
closesocket(sClient);//关闭套接字
WSACleanup();
}
❹ 有关网络游戏服务器的问题
IOCP全称I/O Completion Port,中文译为I/O完成端口。IOCP是一个异步I/O的API,它可以高效地将I/O事件通知给应用程序。与使用select()或是其它异步方法不同的是,一个套接字[socket]与一个完成端口关联了起来,然后就可继续进行正常的Winsock操作了。然而,当一个事件发生的时候,此完成端口就将被操作系统加入一个队列中。然后应用程序可以对核心层进行查询以得到此完成端口。
这里我要对上面的一些概念略作补充,在解释[完成]两字之前,我想先简单的提一下同步和异步这两个概念,逻辑上来讲做完一件事后再去做另一件事就是同步,而同时一起做两件或两件以上事的话就是异步了。你也可以拿单线程和多线程来作比喻。但是我们一定要将同步和堵塞,异步和非堵塞区分开来,所谓的堵塞函数诸如accept(…),当调用此函数后,此时线程将挂起,直到操作系统来通知它,“HEY兄弟,有人连进来了”,那个挂起的线程将继续进行工作,也就符合”生产者-消费者”模型。堵塞和同步看上去有两分相似,但却是完全不同的概念。大家都知道I/O设备是个相对慢速的设备,不论打印机,调制解调器,甚至硬盘,与CPU相比都是奇慢无比的,坐下来等I/O的完成是一件不甚明智的事情,有时候数据的流动率非常惊人,把数据从你的文件服务器中以Ethernet速度搬走,其速度可能高达每秒一百万字节,如果你尝试从文件服务器中读取100KB,在用户的眼光来看几乎是瞬间完成,但是,要知道,你的线程执行这个命令,已经浪费了10个一百万次CPU周期。所以说,我们一般使用另一个线程来进行I/O。重叠IO[overlappedI/O]是Win32的一项技术,你可以要求操作系统为你传送数据,并且在传送完毕时通知你。这也就是[完成]的含义。这项技术使你的程序在I/O进行过程中仍然能够继续处理事务。事实上,操作系统内部正是以线程来完成overlapped I/O。你可以获得线程所有利益,而不需要付出什么痛苦的代价。
完成端口中所谓的[端口]并不是我们在TCP/IP中所提到的端口,可以说是完全没有关系。我到现在也没想通一个I/O设备[I/ODevice]和端口[IOCP中的Port]有什么关系。估计这个端口也迷惑了不少人。IOCP只不过是用来进行读写操作,和文件I/O倒是有些类似。既然是一个读写设备,我们所能要求它的只是在处理读与写上的高效。
❺ Linux下Socket编程 怎样实现客户端之间互相通信
网络的Socket数据传输是一种特殊的I/O,Socket也是一种文件描述符。Socket也具有一个类似于打开文件的函数调用Socket(),该函数返回一个整型的Socket描述符,随后的连接建立、数据传输等操作都是通过该Socket实现的。
下面用Socket实现一个windows下的c语言socket通信例子,这里我们客户端传递一个字符串,服务器端进行接收。
【服务器端】
#include"stdafx.h"
#include<stdio.h>
#include<winsock2.h>
#include<winsock2.h>
#defineSERVER_PORT5208//侦听端口
voidmain()
{
WORDwVersionRequested;
WSADATAwsaData;
intret,nLeft,length;
SOCKETsListen,sServer;//侦听套接字,连接套接字
structsockaddr_insaServer,saClient;//地址信息
char*ptr;//用于遍历信息的指针
//WinSock初始化
wVersionRequested=MAKEWORD(2,2);//希望使用的WinSockDLL的版本
ret=WSAStartup(wVersionRequested,&wsaData);
if(ret!=0)
{
printf("WSAStartup()failed! ");
return;
}
//创建Socket,使用TCP协议
sListen=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(sListen==INVALID_SOCKET)
{
WSACleanup();
printf("socket()faild! ");
return;
}
//构建本地地址信息
saServer.sin_family=AF_INET;//地址家族
saServer.sin_port=htons(SERVER_PORT);//注意转化为网络字节序
saServer.sin_addr.S_un.S_addr=htonl(INADDR_ANY);//使用INADDR_ANY指示任意地址
//绑定
ret=bind(sListen,(structsockaddr*)&saServer,sizeof(saServer));
if(ret==SOCKET_ERROR)
{
printf("bind()faild!code:%d ",WSAGetLastError());
closesocket(sListen);//关闭套接字
WSACleanup();
return;
}
//侦听连接请求
ret=listen(sListen,5);
if(ret==SOCKET_ERROR)
{
printf("listen()faild!code:%d ",WSAGetLastError());
closesocket(sListen);//关闭套接字
return;
}
printf("Waitingforclientconnecting! ");
printf("Tips:Ctrl+ctoquit! ");
//阻塞等待接受客户端连接
while(1)//循环监听客户端,永远不停止,所以,在本项目中,我们没有心跳包。
{
length=sizeof(saClient);
sServer=accept(sListen,(structsockaddr*)&saClient,&length);
if(sServer==INVALID_SOCKET)
{
printf("accept()faild!code:%d ",WSAGetLastError());
closesocket(sListen);//关闭套接字
WSACleanup();
return;
}
charreceiveMessage[5000];
nLeft=sizeof(receiveMessage);
ptr=(char*)&receiveMessage;
while(nLeft>0)
{
//接收数据
ret=recv(sServer,ptr,5000,0);
if(ret==SOCKET_ERROR)
{
printf("recv()failed! ");
return;
}
if(ret==0)//客户端已经关闭连接
{
printf("Clienthasclosedtheconnection ");
break;
}
nLeft-=ret;
ptr+=ret;
}
printf("receivemessage:%s ",receiveMessage);//打印我们接收到的消息。
}
//closesocket(sListen);
//closesocket(sServer);
//WSACleanup();
}
【客户端】
#include"stdafx.h"
#include<stdio.h>
#include<stdlib.h>
#include<winsock2.h>
#defineSERVER_PORT5208//侦听端口
voidmain()
{
WORDwVersionRequested;
WSADATAwsaData;
intret;
SOCKETsClient;//连接套接字
structsockaddr_insaServer;//地址信息
char*ptr;
BOOLfSuccess=TRUE;
//WinSock初始化
wVersionRequested=MAKEWORD(2,2);//希望使用的WinSockDLL的版本
ret=WSAStartup(wVersionRequested,&wsaData);
if(ret!=0)
{
printf("WSAStartup()failed! ");
return;
}
//确认WinSockDLL支持版本2.2
if(LOBYTE(wsaData.wVersion)!=2||HIBYTE(wsaData.wVersion)!=2)
{
WSACleanup();
printf("InvalidWinSockversion! ");
return;
}
//创建Socket,使用TCP协议
sClient=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(sClient==INVALID_SOCKET)
{
WSACleanup();
printf("socket()failed! ");
return;
}
//构建服务器地址信息
saServer.sin_family=AF_INET;//地址家族
saServer.sin_port=htons(SERVER_PORT);//注意转化为网络节序
saServer.sin_addr.S_un.S_addr=inet_addr("192.168.1.127");
//连接服务器
ret=connect(sClient,(structsockaddr*)&saServer,sizeof(saServer));
if(ret==SOCKET_ERROR)
{
printf("connect()failed! ");
closesocket(sClient);//关闭套接字
WSACleanup();
return;
}
charsendMessage[]="hellothisisclientmessage!";
ret=send(sClient,(char*)&sendMessage,sizeof(sendMessage),0);
if(ret==SOCKET_ERROR)
{
printf("send()failed! ");
}
else
printf("clientinfohasbeensent!");
closesocket(sClient);//关闭套接字
WSACleanup();
}
❻ 如何在socket的基础上实现两台主机之间的通讯
用VB5中WinSock控件编写网上聊天程序
Sockets是在Unix系统上提出来的,一开始主要是用于本地通讯,但很快就应用到C/S体系上。MicroSoft公司在此基础上创建了WinSock控件,专门用于Windows接口,与Sockets完全兼容。Winsock控件对用户来说是不可见的,它提供了访问 TCP 和 UDP 网络服务的方便途径。Microsoft Access、Visual Basic、Visual C++ 或 Visual FoxPro 的开发人员都可使用它。为编写客户或服务器应用程序,不必了解 TCP 的细节或调用低级的 Winsock APIs。通过设置控件的属性并调用其方法就可轻易连接到一台远程机器上去,并且还可双向交换数据。下面就利用VB5中的WinSock控件编写一个网上聊天程序。
一)网络通信协议的基础和选择
1.1 TCP(数据传输协议)基础
数据传输协议允许创建和维护与远程计算机的连接。连接两台计算机就可彼此进行数据传输。
如果创建客户应用程序,就必须知道服务器计算机名或者 IP 地址(RemoteHost 属性),还要知道进行“侦听”的端口(RemotePort 属性),然后调用 Connect 方法。
如果创建服务器应用程序,就应设置一个收听端口(LocalPort 属性)并调用 Listen 方法。当客户计算机需要连接时就会发生 ConnectionRequest 事件。为了完成连接,可调用 ConnectionRequest 事件内的 Accept 方法。
建立连接后,任何一方计算机都可以收发数据。为了发送数据,可调用 SendData 方法。当接收数据时会发生 DataArrival 事件。调用 DataArrival 事件内的 GetData 方法就可获取数据。
1.2 UDP(用户数据文报协议)基础
用户数据文报协议 (UDP) 是一个无连接协议。跟 TCP 的操作不同,计算机并不建立连接。另外 UDP 应用程序可以是客户机,也可以是服务器。
为了传输数据,首先要设置客户计算机的 LocalPort 属性。然后,服务器计算机只需将 RemoteHost 设置为客户计算机的 Internet 地址,并将 RemotePort 属性设置为跟客户计算机的 LocalPort 属性相同的端口,并调用 SendData 方法来着手发送信息。于是,客户计算机使用 DataArrival 事件内的 GetData 方法来获取已发送的信息。
1.3 选择通讯协议
在使用 WinSock 控件时,首先需要考虑使用什么协议。可以使用的协议包括 TCP 和 UDP。两种协议之间的重要区别在于它们的连接状态:
TCP 协议是有连接的协议,可以将它同电话系统相比。在开始数据传输之前,用户必须先建立连接。
UDP 协议是一种无连接协议,两台计算机之间的传输类似于传递邮件:消息从一台计算机发送到另一台计算机,但是两者之间没有明确的连接。另外,单次传输的最大数据量取决于具体的网络。
到底选择哪一种协议通常是由需要创建的应用程序决定的。下面的几个问题将有助于选择适宜的协议:
1. 在收发数据的时候,应用程序是否需要得到客户端或者服务器的确认信息?如果需要,使用 TCP 协议,在收发数据之前先建立明确的连接。
2. 数据量是否特别大(例如图象与声音文件)?在连接建立之后,TCP 协议将维护连接并确保数据的完整性。不过,这种连接需要更多的计算资源,因而是比较“昂贵”的。
3. 数据发送是间歇的,还是在一个会话内?例如,如果应用程序在某个任务完成的时候需要通知某个计算机,UDP 协议是更适宜的。UDP 协议适合发送少量的数据。
通讯协议的选择是通过设置WinSock的Protocol属性来实现的。下面选择TCP通讯协议编写网上聊天程序,在此之前必须知道一个极其重要的参数---服务器端的IP地址或计算机名。
二)确定计算机的名字
1. 在计算机的桌面上,右键单击“网上邻居”。
2. 选择“属性”。
3. 单击“标识”选项卡。
4. 在“计算机名称”框中可以找到计算机的名称。
确定计算机的 IP地址
1. 单击“任务条”上的“启动”。
2. 选择“运行”。
3. 若服务器端操作系统为win95则在“打开”中填入“winipcfg”,若服务器端操作系统为winnt则在“打开”中填入“ipconfig”。
4. 按下“确定”键。
上面找到的计算机名称或IP地址可以作为WinSock的RemoteHost 属性的值。
三) winsock控件的State属性。
state 属性的设置值是: 常 数
值 描 述
sckclosed 0 缺省的。关闭
sckopen 1 打开
scklistening 2 侦听
sckconnectionpending 3 连接挂起
sckresolvinghost 4 识别主机
sckhostresolved 5 已识别主机
sckconnecting 6 正在连接
sckconnected 7 已连接
sckclosing 8 同级人员正在关闭连接
sckerror 9 错误
下面主要要用到sckClosed.sckConnected两个State属性的值。
四)网上聊天程序的编制
4.1 程序中服务器端所起的作用。
从图示中可以看到服务器端的两个winsock控件之间并不存在直接的通讯,同时sckServer1和sckClient2及sckServer2和sckClient1之间是不能直接通讯的。这也即是说若sckClient1向sckClient2发出信息,信息首先被sckServer1接受,sckServer1再将信息传给程序的信息处理部分,信息处理部分再将处理好的信息传给sckServer2,再由sckServer2传给sckClient2。反之亦然。那么服务器端的信息处理部分又进行什么工作呢?
1. 对通讯的通道数作一些限制。
2. 对使用后已关闭的通道,必须能够重新使用以节省资源。
3. 必须对所传递的数据包信息作甑别,从而作出不同的处理。
通过解开数据的包头就可区分不同的信息。
网上聊天有两种方式:第一种,以广播方式;第二种,以点对点的方式。广播方式即所有客户都能收到某一客户发出的信息。点对点的方式即想说“悄悄话”的一对客户专门开辟了一间谈话的“小屋”,别的客户不能“听”到他们的谈话。在下面的程序中将看到如何利用数据的不同包头来区分用户是想以广播方式还是以点对点的方式进行谈话的(点对点方式数据的包头为“PT”,广播方式则无包头)。
4.2 客户端的程序
1. 在客户端创建一个新的工程将其命名为“ClientPrj”
2. 将缺省窗体命名为 frmClient。
3. 将窗体的标题改为“Client”。
4. 在窗体中添加一个 WinSock 控件,并将其命名为 tcpClient。
5. 在 frmClient 中添加一个ListBox 控件。将其命名为lstReceive。
6. 在 frmClient 中添加一个 TextBox 控件。将其命名为 txtSend。
7. 在窗体上放两个 CommandButton 控件,并将其命名为 cmdConnect和cmdSent。
8. 将cmdConnect控件的标题改为 Connect, 将cmdSent控件的标题改为 Sent。
9. 在窗体中添加如下的代码。
Private Sub cmdConnect_Click()
On Error GoTo ErrorPro
sckClient.Connect
Exit Sub
ErrorPro:
MsgBox "服务器未开或网络出错!"
End
End Sub
Private Sub cmdSent_Click()
sckClient.SendData txtSent.Text
End Sub
Private Sub Form_Load()
' RemoteComputerName为服务器端的计算机名或IP地址。
sckClient.RemoteHost = "RemoteComputerName"
sckClient.RemotePort = 1000
End Sub
Private Sub sckClient_Close()
MsgBox "服务器通道已关闭!"
End
End Sub
Private Sub sckClient_Connect()
MsgBox "连接成功!"
cmdConnect.Enabled = False
End Sub
Private Sub sckClient_DataArrival(ByVal bytesTotal As Long)
Dim s As String
sckClient.GetData s
lstReceive.AddItem s
End Sub
Private Sub sckClient_Error(ByVal Number As Integer, Description As String, ByVal Scode As Long, _ ByVal Source As String, ByVal HelpFile As String, ByVal HelpContext As Long, CancelDisplay As Boolean)
sckClient.Close
cmdConnect.Enabled = True
End Sub
4.3 服务器端的程序
1. 在服务器端创建一个新的工程将其命名为“ServerPrj”。
2. 将缺省窗体命名为“frmServer”。
3. 在窗体中添加一个ListBox控件,将其命名为“lstReceive”。
4. 在窗体中添加三个WinSock控件,将其分别命名为“sckListen”,sckBusy和“sckServer”并将“sckServer”的“Index”属性设置为0。
5. 在窗体中添加如下代码.。
'最大通道数
Private MaxChan As Integer
Private Sub Form_Load()
Dim i As Integer
MaxChan = 10
For i = 1 To MaxChan - 1
Load sckServer(i)
Next i
sckListen.LocalPort = 1000
sckListen.Listen
End Sub
Private Sub sckBusy_Close()
sckBusy.Close
End Sub
Private Sub sckBusy_DataArrival(ByVal bytesTotal As Long)
sckBusy.SendData "服务器忙,请稍后再连接!"
DoEvents
End Sub
Private Sub sckListen_ConnectionRequest(ByVal requestID As Long)
Dim i As Integer
'决定由哪一Winsock接受请求
For i = 0 To MaxChan - 1
If sckServer(i).State = 0 Then
Exit For
End If
Next i
If sckServer(i).State = 0 Then
sckServer(i).Accept requestID
Exit Sub
End If
'如果所有Winsock都用完则由专门的“忙”Winsock接受请求,以免用户要求得不到响应
sckBusy.Close
sckBusy.Accept requestID
End Sub
Private Sub sckListen_Error(ByVal Number As Integer, Description As String, ByVal Scode As Long, _ ByVal Source As String, ByVal HelpFile As String, ByVal HelpContext As Long, CancelDisplay As Boolean)
sckListen.Close
sckListen.LocalPort = 1000
sckListen.Listen
End Sub
Private Sub sckServer_Close(Index As Integer)
sckServer(Index).Close
End Sub
Private Sub sckServer_DataArrival(Index As Integer, ByVal bytesTotal As Long)
Dim s As String
Dim i As Integer
sckServer(Index).GetData s
If UCase(Left(Trim(s), 2)) = "PT" Then '判断是否为悄悄话,点对点方式
If IsNumeric(Mid(Trim(s), 3, 1)) Then
i = Mid(Trim(s), 3, 1)
sckServer(i).SendData "Channel " & Index & " " & Right(Trim(s), Len(Trim(s)) - 3)
DoEvents
End If
Else '广播方式
For i = 0 To MaxChan - 1
'利用winsock的State属性给所有连接在服务器上的客户发消息
If sckServer(i).State = 7 Then
sckServer(i).SendData "Channel " & Index & " " & Trim(s)
DoEvents
End If
Next i
End If
lstReceive.AddItem "Channel " & Index & " " & Trim(s)
End Sub
Private Sub sckServer_Error(Index As Integer, ByVal Number As Integer, Description As String, _
ByVal Scode As Long, ByVal Source As String, ByVal HelpFile As String, ByVal HelpContext As _
Long, CancelDisplay As Boolean)
sckServer(Index).Close
End Sub
从程序中可以看到:第一,程序中限制了通道数(10路)。第二,通过判断WinSock控件的State属性是否为0(关闭状态),来重新使用已关闭的WinSock控件。第三,通过给WinSock控件传递的信息加上包头,来对信息进行不同的处理(程序中若信息前加上了“PT"(Private Talk)+"通道数”的包头,由此就知道客户想要同拥有此“通道数”的另一客户进行“悄悄话”,否则就以广播方式将信息发给所有客户)。
五) 结束语
WinSock控件不仅仅是用来编制网上聊天程序,而且可以用来编制各种网络游戏或网络通信程序。实际上WinSock控件是编制各种C/S程序的利器。在实际使用中通常是将WinSock控件封装在Activex DLL(进程内)、Activex EXE(进程外)部件的类中(类中引用)来使用的。通过区分所传信息前的不同的包头,用RaiseEvent命令引发不同 的事件,再对事件分别进行处理。这样不仅增加了程序的可调试性和安全性,而且更符合事件驱动编程方法的特点。
❼ Qt 2个线程共用1个Socket 分别收发数据可以吗
1:socket句柄就是一个整型,是映射到系统句柄队列里面(你可以认为这个值是一个key,一个key对应一个系统的具体socket结构体),指针是无意义的,比方你创建了一个socket句柄值是10,你直接使用10在任何线程都是调用这个socket,这个映射过程是socket相关api内部完成的,是全局的。
2:多个线程共用一个socket分别处理收发是可以的,很多这样的例子,一些网络IO模型就是一个部分线程负责收数据包,部分线程负责发响应包,但不要多个线程共用一个socket来收,这样会导致问题。
3:你要多线程共享socket句柄,直接传值就行了,不要传引用和指针,不过注意socket关闭的同步处理。最好用一个对象来统一处理每个socket的打开和关闭,读取和发送。所有线程拿着这个对象来操作socket,这样socket的有效性判断都在对象里面处理。不然一个线程关闭了socket,子线程不知道继续拿着这个句柄号在操作就会出问题。
❽ java 编程 网络游戏 socket
UDP只是Socket的一种协议,两者都可以用到,但是ServerSocket是必须用到的,对你的作业,如果只是两人对战,必然一人是ServerSocket(主服务),另外一个是Socket(客户端);如果多人的话,还需要建立单独的服务器,多个客户端之间不直接通信,通过服务器来通信。
❾ java网络版中国象棋Socket传递数据的问题
写一个服务器端作为中转消息用,两个客户端同时连接到服务器端上。
其中一个客户端同时也作为服务器。
作为服务器的一方,
ServerSocket server=new ServerSocket(port);
Socket client=server.accept();//接收到连接之后
启动一个线程负责接收来自客户端的消息。
象棋初始化,开始游戏。
传递数据有很多类型,传递字符串,然后接收之后分析。
用:
BufferedOutputStream bo=new BufferedOutputStream(client.getOutputStream());
bo.write("hellow".getBytes());//发送字符串
bo.flush();//清空缓冲区
读取就用相应的:
BufferedInputStream bi=new BufferedInputStream(client.getInputStream());
byte b[]=new byte[1024];
int len=bi.read(b);
String s1=new String(b,0,len);