该文章叙述的一些问题,主要偏windows方面,不着重与linux的比较,接续在如何用vs08编译ffmpeg这件事情之后。内容大多搜集于网上,为转载。
————————————————————————————————————————————————————
这篇文章列举了些数据结构与接口的相关:windows下网络编程笔记之linux到windows程序移植
————————————————————————————————————————————————————
1. 小问题,其实也不是网络技术问题了:if ((int)fds[i].fd > n),条件真还是假(int n = -1;)?
看看linux下pollfd结构的定义:
struct pollfd {
int fd; /* file des to poll */
short events; /* events to look for */
short revents; /* events that occurred */
};
看看windows下pollfd结构的定义:
typedef struct pollfd {
SOCKET fd;
SHORT events;
SHORT revents;
} WSAPOLLFD, *PWSAPOLLFD, FAR *LPWSAPOLLFD;
typedef UINT_PTR SOCKET;
类型不匹配,导致的隐式转换,在windows下,题中的条件表达式基本恒为真。
2. WSAStartup函数
int WSAStartup(
WORD wVersionRequested,
LPWSADATA lpWSAData
);
3. ffmpeg代码中getaddrinfo函数的使用
#if defined(_WIN32)
{
int (WSAAPI *win_getaddrinfo)(const char *node, const char *service,
const struct addrinfo *hints,
struct addrinfo **res);
char moduleName[36] = {0};
int num_chars = 0;
wchar_t moduleName_w[36] = {0};
snprintf(moduleName, sizeof(moduleName), "ws2_32.dll");//
/* convert UTF-8 to wide chars */
num_chars = MultiByteToWideChar(CP_UTF8, 0, moduleName, -1, NULL, 0);
if (num_chars <= 0)
return -1;
MultiByteToWideChar(CP_UTF8, 0, moduleName, -1, moduleName_w, num_chars);
HMODULE ws2mod = GetModuleHandle((const WCHAR *)moduleName_w);
win_getaddrinfo = GetProcAddress(ws2mod, "getaddrinfo");
if (win_getaddrinfo)
return win_getaddrinfo(node, service, hints, res);
}
#endif
4. 在ioctlsocket设置非阻塞之后,connect 10035(WSAEWOULDBLOCK)错误?
可参考:connect 10035错误
“non blocking模式,connect不会等到成功,而是马上返回。你需要再select()来判断成功与否。
for (i = 0; i < TotalSockets; i++)
FD_SET(SocketArray[i]->Socket, &ReadSet);
if ((Total = select(0, &ReadSet, NULL, NULL, NULL)) == SOCKET_ERROR)
{
printf("select() returned with error %d\n", WSAGetLastError());
return;
}”
“10035不是错误。改变为nonblock模式后第一个改变的观念就是:不能认为凡是遇到SOCKET_ERROR都认为遇到错误了。WSAEWOULDBLOCK是一种正常性的错误码,他告诉你现在这个操作无法立即完成,必须等待后续的通知。你可以通过楼上说的select方式去检查是否链接成功建立”
或看:http://www.verydemo.com/demo_c173_i9565.html
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);//先创建套接字
if(sock == INVALID_SOCKET)
{
AfxMessageBox("创建套接字失败!");
return 0;
}
SOCKADDR_IN addrTo;
addrTo.sin_family=AF_INET;
addrTo.sin_port=htons(4000);
addrTo.sin_addr.S_un.S_addr=inet_addr(ip);
//--------------------------------------------------------------------------
//设置为非阻塞方式连接
unsigned long ul = 1;
int err;
int ret = ioctlsocket(sock, FIONBIO, (unsigned long*)&ul);
if(ret == SOCKET_ERROR)
{
err = WSAGetLastError();
closesocket(sock);
sock = NULL;
return FALSE;
}
TIMEVAL timeval;
fd_set r;
FD_ZERO(&r);
FD_SET(sock, &r);
timeval.tv_sec = 1; //秒
timeval.tv_usec =200; //毫秒
//上面的代码是要connect在1.2秒之后返回,不管是否已经连接上,这样就不会阻塞啦,简单吧
connect(sock, (SOCKADDR*)&addrTo, sizeof(SOCKADDR));
ret = select(0, 0, &r, 0, &timeval);
if ( ret <= 0 )
{
char ch[20] = {0};
sprintf(ch, "和%s连接超时, 取原参数失败", ip);
MessageBox(ch, "错误", MB_ICONSTOP);
err = WSAGetLastError();
closesocket(sock);
sock = NULL;
return FALSE;
}
顺便记录这个问题: How to set a socket connection timeout
是说,有时候connect当目标不能到达,超时太久。就先设置非阻塞,connect立即返回,然后重新设为阻塞,最后做select看看socket是否准备好。
5. 在ffmpeg的dshow中,去枚举设备名,与上层传下来的设备名匹配。
如:汉字的unicode编码,常用汉字的UTF-8编码,汉字GBK编码表。上层获取的是GBK码,下面却用UTF-8去匹配,所以总是失败。
引自 文字编码 ASCII 汉字GB2312 UTF-8解析
“ASCII,美国信息交换标准代码(America standard code of Information Interchange),用一个字节的7位,美国专用。欧洲也要编码,于是字节的8位全用上,有了IBM/ISO Latin-1。然后是第三世界国家,中国,韩国等,于是就必须得扩展了,我们中文辐射区的文字表示甚是复杂,于是两个字节的UNICODE出世。但是在几种编码的兼容问题出现了,怎样让中文的一个文件能在美国读出来呢?一种权衡方案出台--UTF系列。UTF,Universal Transformation Format,通用转换格式。UTF-8是一种非定长的字符表示方式,具体实现可以参见相关资料。”
“ascii码是根据http编码得出的,首先要知道这个字的http编码,先进入百度贴吧,把你想查看的字输入,点击搜索,比如说我输入“牛”,因为地址太长了,再点一下左上角百度贴吧旁的“牛吧”,就会出现比较短的地址,这个地址是 http://tieba.baidu.com/f?kw=%C5%A3 kw=后面的%C5%A3就是http编码,把%去掉,变成C5A3,使用系统自带的计算器把他变为10进制(开始——所有程序——附件——计算器),查看——科学型,先选择十六进制,再输入C5A3,然后选择十进制,上面的数字就会变成50595,也就说alt+50595能打出“牛””
下面贴两段代码,gbk与utf-8的转换,调用了windows下的接口,代码丑陋与否无所谓了。
//using c
char *gbk_to_utf8_c(const char *src_gbk, void *(* local_malloc)(size_t), void (* local_free)(void *))
{
int n;
char *dst_utf8 = NULL;
wchar_t *tmp = NULL;
if (!src_gbk || !local_malloc || !local_free)
{
return NULL;
}
n = MultiByteToWideChar(CP_ACP, 0, src_gbk, -1, NULL, 0);
tmp = (wchar_t *)local_malloc(n*2+2);
memset(tmp, 0, n * 2 + 2);
MultiByteToWideChar(CP_ACP, 0, src_gbk, -1, tmp, n);
n = WideCharToMultiByte(CP_UTF8, 0, tmp, -1, NULL, 0, NULL, NULL);
dst_utf8 = (char *)local_malloc(n+1);
memset(dst_utf8, 0, n + 1);
WideCharToMultiByte(CP_UTF8, 0, tmp, -1, dst_utf8, n, NULL, NULL);
local_free((void *)tmp);
return dst_utf8;
}
char *utf8_to_gbk_c(const char *src_utf8, void *(* local_malloc)(size_t), void (* local_free)(void *))
{
int n = MultiByteToWideChar(CP_UTF8, 0, src_utf8, -1, NULL, 0);
wchar_t *tmp = (wchar_t *)local_malloc(n*2+2);
char *dst_gbk = NULL;
memset(tmp, 0, n * 2 + 2);
MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)src_utf8, -1, (LPWSTR)tmp, n);
n = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)tmp, -1, NULL, 0, NULL, NULL);
dst_gbk = (char *)local_malloc(n+1);
memset(dst_gbk, 0, n + 1);
WideCharToMultiByte(CP_ACP,0, (LPCWSTR)tmp, -1, dst_gbk, n, NULL, NULL);
local_free((void *)tmp);
return dst_gbk;
}
还可以参考: UTF-8, Unicode, GB2312格式串转换之C语言版
除了编码问题,在dshow接口调用的时候,(对于一些硬件设备名,xp win7下不同,win7下通常会有前缀,这样使设备名很长),设备友好名获取不完整,而用dsound接口获取又是没有问题的。下面是dshow调用的部分接口:
*.读取设备名的属性
step1: Call IMoniker::BindToStorage to get a pointer to the IPropertyBag interface.
IPropertyBag *pPropBag;
HRESULT hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag));
step2: Call IPropertyBag::Read to read the property.
VARIANT var;
VariantInit(&var);
// Get description or friendly name.
hr = pPropBag->Read(L"Description", &var, 0);
没辙,在这里做名字匹配的时候,只好通过,两个字串是否包含的关系,去做比较。