蓝牙socket的recv()问题 - C++ Builder / Windows SDK/API
在Windows Mobile6.1系统上做蓝牙,使用socket。
现在搜索、连接、发送都没有问题。接收用的是recv()堵塞,现在的情况是:能收到数据,但每次收几个字节就通知我,完整的一帧(自定义的)要分好多次才能收完。例如发送1234567890,会先收一个字节“1”,再收“234567”,再收“890”这样。
想请教一下,是不是什么参数我没有设置?堵塞接收怎样才能一次接收成功完整的一帧?
源码如下:[code=C/C++][/code]
//
#include <Bt_api.h.>
#include <winioctl.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
#define lengthof(exp) ((sizeof((exp)))/sizeof((*(exp))))
#define IOCTL_SERVICE_STARTCTL_CODE(FILE_DEVICE_SERVICE, 1, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SERVICE_STOPCTL_CODE(FILE_DEVICE_SERVICE, 2, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SERVICE_REFRESHCTL_CODE(FILE_DEVICE_SERVICE, 3, METHOD_BUFFERED, FILE_ANY_ACCESS)
//////////////////////////////////////////////////////////////////////////
//
GUID RFCOMM_PROTOCOL_UUID = {0x00001101, 0x0000, 0x1000, {0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB}};
HKEY m_hKey;
//
HWND m_hwnd_List_Find;
TCHAR wRbuf[64];
//
#define NS_BTH 16
//
#define MAX_NAME 248
//
//
SOCKET m_socket;
//
//
LPWSAQUERYSET pwsaResults;
//
CStringArray csar;
unsigned short g_port;
UINT m_LinkState;//连接活动进行到什么状态
#define DEFAULT_PORT 1
//保存蓝牙设备 BT_ADDR
CArray<BT_ADDR, BT_ADDR> arb;
HWNDhWnd;
BOOLnExit = FALSE;
HANDLEhThread = INVALID_HANDLE_VALUE;
staticDWORD WINAPI ReadThread( PVOID pArg );
IMPLEMENT_DYNCREATE(CBthOpe4View, CFormView)
BEGIN_MESSAGE_MAP(CBthOpe4View, CFormView)
ON_BN_CLICKED(IDC_BUT_FIND, &CBthOpe4View::OnBnClickedButFind)
ON_WM_CLOSE()
ON_BN_CLICKED(IDC_BUT_LINK, &CBthOpe4View::OnBnClickedButLink)
ON_BN_CLICKED(IDC_BTN_SEND, &CBthOpe4View::OnBnClickedBtnSend)
ON_WM_TIMER()
END_MESSAGE_MAP()
// CBthOpe4View 构造/析构
CBthOpe4View::CBthOpe4View()
: CFormView(CBthOpe4View::IDD)
{
// TODO: 在此处添加构造代码
}
CBthOpe4View::~CBthOpe4View()
{
}
void CBthOpe4View::DoDataExchange(CDataExchange* pDX)
{
CFormView::DoDataExchange(pDX);
}
BOOL CBthOpe4View::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: 在此处通过修改
// CREATESTRUCT cs 来修改窗口类或样式
return CFormView::PreCreateWindow(cs);
}
void CBthOpe4View::OnInitialUpdate()
{
CFormView::OnInitialUpdate();
m_LinkState = 0;
SetTimer(1,100,NULL);
GetDlgItem( IDC_LIST_FIND, &m_hwnd_List_Find );
WSADATA wsd;
int ret = WSAStartup( MAKEWORD( 2, 2 ), &wsd );
WCHAR *argPtr = _T("card");
HANDLE hDev = CreateFile (L"BTD0:", GENERIC_READ | GENERIC_WRITE,//打开电源
FILE_SHARE_READ | FILE_SHARE_WRITE,NULL, OPEN_EXISTING, 0, NULL);
if (hDev != INVALID_HANDLE_VALUE)
{
int iErr = DeviceIoControl (hDev, IOCTL_SERVICE_START, argPtr, sizeof(WCHAR) * (wcslen (argPtr) + 1), NULL, NULL, NULL, NULL);
CloseHandle (hDev);
}
nExit = TRUE;
hThread = CreateThread(NULL,0, ReadThread,NULL, 0,NULL);
Sleep(1000);
}
// CBthOpe4View 诊断
#ifdef _DEBUG
void CBthOpe4View::AssertValid() const
{
CFormView::AssertValid();
}
CBthOpe4Doc* CBthOpe4View::GetDocument() const // 非调试版本是内联的
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CBthOpe4Doc)));
return (CBthOpe4Doc*)m_pDocument;
}
#endif //_DEBUG
// CBthOpe4View 消息处理程序
void CBthOpe4View::OnBnClickedButFind()
{
// TODO: 在此添加控件通知处理程序代码
if ( TRUE == m_BSoketFlag )
{
m_BSoketFlag = FALSE;
closesocket( m_socket );
}
((CListBox*)GetDlgItem(IDC_LIST_FIND))->ResetContent();
GetDlgItem(IDC_BUT_FIND)->EnableWindow( FALSE );
PerformInquiry();
GetDlgItem(IDC_BUT_FIND)->EnableWindow( TRUE );
}
//////////////////////////////////////////////////////////////////////////
BOOL CBthOpe4View::Open( )
{
unsigned int channel = 0;
//创建TCP套接字
m_socket = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
if (m_socket == INVALID_SOCKET)
return FALSE;
return TRUE;
}
//查询蓝牙设备
BOOL CBthOpe4View::PerformInquiry()
{
int ret ;
int count = 0;
int retry = 0 ;
arb.RemoveAll();
csar.RemoveAll();
WSAQUERYSET wsaq;
HANDLE hLookup;
union {
CHAR buf[5000];
double __unused; // ensure proper alignment
};
Open();
/*LPWSAQUERYSET*/ pwsaResults = (LPWSAQUERYSET) buf;
DWORD dwSize = sizeof(buf);
BOOL bHaveName;
//搜索其它蓝牙设备
ZeroMemory(&wsaq, sizeof(wsaq));
wsaq.dwSize = sizeof(wsaq);
wsaq.dwNameSpace = NS_BTH;
wsaq.lpcsaBuffer = NULL;
ret = WSALookupServiceBegin(&wsaq, LUP_CONTAINERS, &hLookup);
if(ERROR_SUCCESS != ret)
{
wprintf(L"WSALookupServiceBegin failed %d\r\n", GetLastError());
return FALSE;
}
ZeroMemory(pwsaResults, sizeof(WSAQUERYSET));
pwsaResults->dwSize = sizeof(WSAQUERYSET);
pwsaResults->dwNameSpace = NS_BTH;
pwsaResults->lpBlob = NULL;
while (1)
{
ret = WSALookupServiceNext(hLookup,
LUP_RETURN_NAME | LUP_RETURN_ADDR,
&dwSize, pwsaResults);
if(ret != ERROR_SUCCESS)
{
ret = WSAGetLastError();
break;
}
ASSERT (pwsaResults->dwNumberOfCsAddrs == 1);
BT_ADDR b = ((SOCKADDR_BTH *)pwsaResults->lpcsaBuffer->RemoteAddr.lpSockaddr)->btAddr;
g_port = ((sockaddr_in*)pwsaResults->lpcsaBuffer->RemoteAddr.lpSockaddr)->sin_port;
//if(g_port == 0)
g_port = DEFAULT_PORT;
bHaveName = pwsaResults->lpszServiceInstanceName && *(pwsaResults->lpszServiceInstanceName);
// for test
arb.Add( b );
WCHAR szDevice[MAX_NAME+25];
wsprintf (szDevice, L"%s%s%04x%08x%s", bHaveName ? pwsaResults->lpszServiceInstanceName : L"",
bHaveName ? L"(" : L"", GET_NAP(b), GET_SAP(b), bHaveName ? L")" : L"");
CString csDevice = szDevice;
// for test
csar.Add( csDevice );
ListBox_AddString( m_hwnd_List_Find, csDevice);
//MessageBox(csDevice);
count ++ ;
}
WSALookupServiceEnd(hLookup);
if(!count)
{
AfxMessageBox(_T("搜索失败"));
return FALSE ;
}
return TRUE;
}
[解决办法]
他本身就是流式协议,每次接受字节数不定,需要自己判断是否接收完整。