两道高难度题,悬奖300分。急啊!

JJONY 2000-03-27 04:04:00
这一道问题,我会给300分的分两次给
两个问题是有牵连的。
1、大家也许用过mouse_event这个函数,用来激发鼠标事件的。它有两种激发方式:
 一是用0~65535的屏幕映射值,二是用偏移值,可是无论用哪一种方式都好像不能完全模 拟手工移动鼠标的那种可以看得见移动轨迹。例如:从(100,100)移动到(24,400)的 这个过程中用mouse_event就会一下跳到(24,400)这个坐标里了,但是用手工的话无论移动多快都可以看到一个鼠标的轨迹。
 那我要完全模仿手工鼠标移动该如果实现呢?就是具有加速度的鼠标移动。

2、网络的数据传问题:
 就是说第一题mouse_event的移动数据是从网络的另一台机器上传过来的。执行mouse_event函数的这一方是客户端,发送方是服务器端。双方是采用有连接(STREAM)方式连接的,客户方是采用Winsock 2.0版,网络事件是用WSAEventSelect产生的。没有FD_READ事件,接收数据是用重叠I/O方式和完成例程中嵌套WSARecv函数来完成的。我这样做是为了实时地完成数据接收的任务(书上说的),但是我用了以后好像没有感觉到速度快了。如果速度不够快的话,鼠标的移动就会一跳一跳的不平滑。
 那么我应该怎么样才可以实现网络实时传送数据呢?

上面所完成的功能在一个软件上就已经实现了,而且实现得很好。在一台机器上操纵另一个机器的鼠标几乎是本机操纵似的。
这个软件(客户方和服务方)我给dumpbin了。网络上用了以下的函数:
WSAEventSelect
WSACloseEvent
WSACreateEvent
WSASocketA
WSAWaitForMultipleEvents
WSAEnumNetworkEvents
WSAResetEvent
WSASetEvent
WSAIoctl
奇怪的是这个软件居然没有用WSARecv(recv)和WSASend(send),那它是怎么发送的呢?
但是它有用ReadFile和WriteFile两个函数。
请高手们为我解决吧,起码给我说说个原理啦。拜托,拜托。
...全文
471 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
telan 2000-03-29
  • 打赏
  • 举报
回复
补充一下:

上述代码拷贝过来时,不知道为什么或符号: and 怎么
变成了单词"and"?
telan 2000-03-29
  • 打赏
  • 举报
回复
1.下面是用Winsock2发送数据的函数,我在使用过程中没有发现问题;
2.如果你要求实时性非常好,因为TCP协议的Nagle算法会等待发送数据
到一定数量才真正发送出去,你可以用
setsockopt函数来设置 TCP_NODELAY 参数来禁止发送延迟的Nagle算法,
你可以试一下是否有用。
3.用ReadFile和WriteFile函数确实可以读写SOCKET,但微软强烈建议不要
这样做。

//一次性发送数据(重叠IO)
int SE_SendLL(SOCKET SockFD, char const * pszBuffer, int iBufferSize)
{
DWORD dwRtxBytes = 0;
WSABUF WSABuff;

ZeroMemory(WSABuff,sizeof(WSABUF));
WSABuff.len = iBufferSize;
WSABuff.buf = (char *) pszBuffer;

return ((WSASend(SockFD, &WSABuff, 1, &dwRtxBytes, 0,
NULL, NULL) == 0) ? (int) dwRtxBytes : -WSAGetLastError());

}

// 发送数据
int SE_SendData(SOCKET SockFD, char const * pszBuffer, int iBufferSize, DWORD dwTimeout /* = SE_SEND_TIMEOUT */)
{

HANDLE hWriteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

if (hWriteEvent == NULL)
{
..............
return (-1);
}

int iSendBytes = 0;

for (;;)
{
////////////////////////////////////////////////////////////////
// 发送数据成功
if ((iSendBytes = SE_SendLL(SockFD, pszBuffer, iBufferSize)) >= 0)
break;

int iErrorCode = -iSendBytes;

if (iErrorCode != WSAEWOULDBLOCK)
{
CloseHandle(hWriteEvent);
..............
return (-1);
}

Sleep(100);


// 注册FD_WRITE and FD_CLOSE 事件
if( WSAEventSelect(SockFD, (WSAEVENT) hWriteEvent, FD_WRITE and FD_CLOSE) == SOCKET_ERROR)
{
CloseHandle(hWriteEvent);
..............
return (-1);
}

// 等待事件发生
DWORD dwWaitResult = WSAWaitForMultipleEvents(1, &hWriteEvent, TRUE,
dwTimeout, TRUE);

if (dwWaitResult != WSA_WAIT_EVENT_0)
{
// 清除网络事件
WSAEventSelect(SockFD, (WSAEVENT) hWriteEvent, 0);

CloseHandle(hWriteEvent);
...........
return (-1);
}

WSANETWORKEVENTS NetEvent;
if(WSAEnumNetworkEvents(SockFD,(WSAEVENT)hWriteEvent,&NetEvent) == SOCKET_ERROR)
{
// 清除网络事件
WSAEventSelect(SockFD, (WSAEVENT) hWriteEvent, 0);

CloseHandle(hWriteEvent);
.................
return (-1);
}
if( ( NetEvent.lNetworkEvents == FD_CLOSE ) and and
( NetEvent.lNetworkEvents == FD_WRITE &&
NetEvent.iErrorCode[FD_WRITE_BIT] !=0 ) ) // 发生错误
{
// 清除网络事件
WSAEventSelect(SockFD, (WSAEVENT) hWriteEvent, 0);

CloseHandle(hWriteEvent);
.......................

return (-1);
}
// 清除网络事件
WSAEventSelect(SockFD, (WSAEVENT) hWriteEvent, 0);

}

CloseHandle(hWriteEvent);

return (iSendBytes);
}

//发送完所有数据或超时
int SE_Send(SOCKET SockFD, char const * pszBuffer, int iBufferSize, DWORD dwTimeout /* = SE_SEND_TIMEOUT */)
{

int iRtxBytes = 0;

while (iRtxBytes < iBufferSize)
{
int iRtxCurrent = SE_SendData(SockFD, pszBuffer + iRtxBytes,
iBufferSize - iRtxBytes, dwTimeout);

if (iRtxCurrent < 0)
return (iRtxBytes);

iRtxBytes += iRtxCurrent;
}

return (iRtxBytes);
}
OpenBall 2000-03-29
  • 打赏
  • 举报
回复
1、数控机床技术中有“插补”的名词,从一点到另一点,你可以中间适当多设些点,两点间的移动化为多点的移动,即可。
2、提醒一点,鼠标地连续性可以在这样的情况下实现,即令一台机子的动作可能都比第一台之后几秒钟,但是全部的鼠标事件都滞后,总得却是连续的。
我做过一个局域网传声音的程序,用的方法是:录音由一个线程完成,发送由一个线程完成,数据通过一个队列在内存中作交换。
我想,如果你把本纪的鼠标事件放入队列,启动一个线程发送数据,连续性应该好一点。
JJONY 2000-03-29
  • 打赏
  • 举报
回复
还有要向上面给我解答鼠标移动问题的朋友们说明一下:
解决该问题的方法是采用VxD在Ring0环中截取鼠标偏移数据,然后用SHELL_Message函数(VxD中的服务)发送到Ring 3环的窗口中,这样,鼠标所移动的轨迹就全部截获下来了。在客户方收到了数据后,调用DeviceIoControl函数来模拟鼠标移动,因为执行鼠标动作的环境是在Ring 0环,所以不管当前是处于哪一个VM都会有鼠标的事件产生。
Un1 2000-03-29
  • 打赏
  • 举报
回复
问题一:

从(100,100)移动到(24,400)不要只有一次mouse_event,应该有多次,你可取(400-100)/次数作为参数调用mouse_event.

问题二:

各位大吓已经说的很好了,我有个补充就是如果你觉得还不够快的话使用UDP协议,因为这里要求的实时性可能强于确切性。
JJONY 2000-03-29
  • 打赏
  • 举报
回复
感谢各位大虾们的顶力相助,小弟的问题已经完满解决。答者有分,其中特别感谢telan和janven两位提供的方法。

此外,janven同志你的分数我会马上通知你来拿。

今天,非常高兴能够解决我的问题,所以谁说csdn没有高手?!呵呵。。。。。
Janven 2000-03-29
  • 打赏
  • 举报
回复
对了,你应该在执行前将客户机的鼠标速度设为服务机一致,执行完毕再还原回来。试试看,肯定行的。当然鼠标参数得从服务机传过去。
Janven 2000-03-29
  • 打赏
  • 举报
回复
采用“服务质量”的技术是专门解决需要大带宽的多媒体数据传输,可以向网络服务提供者申请传输带宽以达到你的实时要求。这正是Winsock 2.0能够实现的一项功能。
weity 2000-03-29
  • 打赏
  • 举报
回复
关注
JJONY 2000-03-28
  • 打赏
  • 举报
回复
加速度,谁可以给出详细的程序?还有网络部分的问题请大家回答一下吧。
JJONY 2000-03-28
  • 打赏
  • 举报
回复
everyday,你可以说清楚点吗?我是怎么可以得到加速度呢?
Shania 2000-03-28
  • 打赏
  • 举报
回复
bokei是对的,如果你要使它有加速度的感觉,则可以在循环中每次增加两点之间的距离。
Everyday 2000-03-28
  • 打赏
  • 举报
回复
鼠标的加速度也可以模拟呀,用bokei的方法,你只要设一个全局变量longth来控制你一次setcursorpos的距离,加一个现在是否接受消息的bool变量ttt,再在onmousemove里加个东西,
一个向onmousemove以外的事件发出一个消息,接收以后再settimer一次,时间到了就把longth加一次,就看你控制加速度的大小了,加完了就killtimer和将ttt置为可接受消息,
JJONY 2000-03-28
  • 打赏
  • 举报
回复
olo:不断地调用GetCursorPos是行不通的。因为我还要有鼠标点击事件,当然鼠标点可 以另外处理,这样程序不就太复杂了吗?何况我所Dumpbin的那个软件上在服务器方没有用GetCursorPos这个函数。

bokei:对我也有这个想法,但是手工移动鼠标还有一个加速度的问题呀。忽略了加速度就不能得到像手工移动鼠标的效果。

SoftDIY:我不太会用CSocketFile类,也没有时间去学习它,你可以给我介绍一下吗,帮人帮到底啦。还有,我没记错的话,MFC中的Socket类好像是封装Winsock 1.1版的Socket,Winsock 1.1在高速发送数据时会有掉数据的现象,即使是用可靠连接方式。

harley:我看不懂你的意思。
harley 2000-03-27
  • 打赏
  • 举报
回复

你的问题是使用winsock 不对。在发送是可以随时调用send函数,接受是可的等待
socket 的消息。
SoftDIY 2000-03-27
  • 打赏
  • 举报
回复
File transfer by CSocket function,wish this can help u
void SendFile()
{
#define PORT 34000 /// Select any free port you wish

AfxSocketInit(NULL);
CSocket sockSrvr;
sockSrvr.Create(PORT); // Creates our server socket
sockSrvr.Listen(); // Start listening for the client at PORT
CSocket sockRecv;
sockSrvr.Accept(sockRecv); // Use another CSocket to accept the connection


CFile myFile;
myFile.Open("C:\\ANYFILE.EXE", CFile::modeRead and CFile::typeBinary);

int myFileLength = myFile.GetLength(); // Going to send the correct File Size

sockRecv.Send(&myFileLength, 4); // 4 bytes long

byte* data = new byte[myFileLength];

myFile.Read(data, myFileLength);

sockRecv.Send(data, myFileLength); //Send the whole thing now

myFile.Close();
delete data;

sockRecv.Close();
}


void GetFile()
{
#define PORT 34000 /// Select any free port you wish

AfxSocketInit(NULL);
CSocket sockClient;
sockClient.Create();
sockClient.Connect("127.0.0.1", PORT); // "127.0.0.1" is the IP to your server, same port

int dataLength;
sockClient.Receive(&dataLength, 4); //Now we get the File Size first

byte* data = new byte[dataLength];
sockClient.Receive(data, dataLength); //Get the whole thing

CFile destFile("C:\\temp\\ANYFILE.EXE", CFile::modeCreate and CFile::modeWrite and CFile::typeBinary);

destFile.Write(data, dataLength); // Write it

destFile.Close();

delete data;
sockClient.Close();
}
bokei 2000-03-27
  • 打赏
  • 举报
回复
移动的轨迹其实是在一条直线上.只要知道两点的坐标,求出这条直线的参数,再用循环不断的计算鼠标的位置就可以了.
olo 2000-03-27
  • 打赏
  • 举报
回复
不停地GetCursorPos,那边再SetCursorPos不就有轨迹了吗?

16,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

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