跨平台网络通讯要注意的地方:(以bsd unix与winsock2为例)
1. 套接口数据类型和错误数值
为了保持与 BSD 的兼容性,应用程序可以加入以下一行代码:
#define INVALID_SOCKET -1
例如:
BDS 风格
m_hSocket=socket(…);
if(m_hSocket=-1) /* or m_hSocket<0 */
{…}
Windows风格:
m_hSocket=socket(…);
if(m_hSocket=INVALID_SOCKET)
{…}
BDS 风格
m_hSocket=socket(…);
if(m_hSocket=-1) /* or m_hSocket<0 */
{…}
Windows风格:
m_hSocket=socket(…);
if(m_hSocket=INVALID_SOCKET)
{…}
2. select() 函数和FD_*宏
常用FD_*宏来防止错误。
3. 错误代码-errno,h_errno,WSAGetLastError()
为了保持与 BSD 的兼容性,应用程序可以加入以下一行代码:
#define WSAGetLastError() errno
例如:
BSD风格:
retcode=recv(…);
if(retcode=-1 && errno=EWOULDBLOCK)
{…}
Windows风格:
retcode=recv(…);
if(retcode=-1 && WSAGetLastError ()=EWOULDBLOCK)
{…}
BSD风格:
retcode=recv(…);
if(retcode=-1 && errno=EWOULDBLOCK)
{…}
Windows风格:
retcode=recv(…);
if(retcode=-1 && WSAGetLastError ()=EWOULDBLOCK)
{…}
4 重命名的函数
#define closesocket(a) close(a)
#define ioctlsocket ioctl
5 阻塞
windows虽然支持阻塞,但常用的是非阻塞,而bsd socket默认是阻塞的。
6 头文件与库
window下只需加载头文件winsock2.h, 但在链接时要加载依赖库:ws2_32.lib; linux下网络通讯模块是包含在基本的系统库里了,只需根据调用函数包含不同的头文件即可了。
下面是一个在linux与windows下都能运行的跨平台网络程序范例:
/**/
/**********************************************************
* socket_test.cpp for test socket on windows and linux
* Copyright (C) |2006-11-9| by denny <wqf363@hotmail.com>
**********************************************************/
#include < stdio.h >
#include < string .h >
#ifndef WIN32
#include < sys / socket.h >
#include < unistd.h >
#include < netinet / in .h >
#include < arpa / inet.h >
#include < pthread.h >
#define closesocket(a) close(a)
#else
#include < winsock2.h >
#endif
#define MAXBUF 512
#define PORT 2222
typedef void * ( * tc_thread_func)( void * );
void rcv(); /**/ /*后台接收消息的函数 */
void snd(); /**/ /*发送消息的函数*/
/**/ /*简介:该程序是一个跨平台的一个简单的基于UDP协议聊天工具
功能:主线程:发送消息
子线程:接收消息
作者:wjfree
使用:运行后发送消息:IP +空格+ Message
编译:linux 下:gcc ./chatlin.c -lpthread -o chat
win下:在lcc下添加工程,编译
*/
int main ()
... {
#ifdef WIN32
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD( 2, 2 );
int err = WSAStartup( wVersionRequested, &wsaData );
HANDLE hThread;
DWORD dwThreadId;
hThread= CreateThread(NULL,0, (LPTHREAD_START_ROUTINE)rcv,NULL,0,&dwThreadId);
snd();
WSACleanup();
#else
pthread_t id;
int ret;
ret = pthread_create(&id,NULL,(tc_thread_func)rcv,NULL); /**//*创建一个线程*/
snd();
#endif
return 0;
}
/**/ /*函数:snd()
功能:用scanf()函数接收ip地址和消息内容,发到对应的IP上
作者:wjfree
*/
void snd()
... {
struct sockaddr_in name;
int sock;
name.sin_family = PF_INET;
name.sin_port = htons(PORT);
sock = socket(PF_INET, SOCK_DGRAM,0);
if (sock < 0)
...{
printf("make socket error ");
return;
}
while(1)
...{
char bufloc[MAXBUF];
char ipaddr[17];
scanf("%s%s" , ipaddr, bufloc);
int i = name.sin_addr.s_addr = inet_addr(ipaddr);
if (i == -1)
...{
printf("IP address format error! ");
}
else
...{
int i = sendto(sock, bufloc, strlen(bufloc), 0, (struct sockaddr *)&name, sizeof(name));
if (i < 0)
printf("Can not send the message to %s ", ipaddr);
}
}
closesocket(sock);
}
/**/ /*函数:snd()
功能:接收消息并显示在终端
作者:wjfree
*/
void rcv()
... {
struct sockaddr_in RecvAddr;
struct sockaddr_in SenderAddr;
int sock;
sock = socket(AF_INET, SOCK_DGRAM, 0);
RecvAddr.sin_family = AF_INET;
RecvAddr.sin_port = htons(PORT);
RecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(sock, (struct sockaddr *) &RecvAddr, sizeof(RecvAddr));
printf("Receiving datagrams... ");
while(1)
...{
int size = sizeof(SenderAddr);
char RecvBuf[MAXBUF];
int BufLen = MAXBUF;
int i = recvfrom(sock,
RecvBuf,
BufLen,
0,
(struct sockaddr *)&SenderAddr,
(size_t*)&size);
RecvBuf[i] = 0;
printf("%s: %s ", inet_ntoa(SenderAddr.sin_addr),RecvBuf);
}
closesocket(sock);
}
* socket_test.cpp for test socket on windows and linux
* Copyright (C) |2006-11-9| by denny <wqf363@hotmail.com>
**********************************************************/
#include < stdio.h >
#include < string .h >
#ifndef WIN32
#include < sys / socket.h >
#include < unistd.h >
#include < netinet / in .h >
#include < arpa / inet.h >
#include < pthread.h >
#define closesocket(a) close(a)
#else
#include < winsock2.h >
#endif
#define MAXBUF 512
#define PORT 2222
typedef void * ( * tc_thread_func)( void * );
void rcv(); /**/ /*后台接收消息的函数 */
void snd(); /**/ /*发送消息的函数*/
/**/ /*简介:该程序是一个跨平台的一个简单的基于UDP协议聊天工具
功能:主线程:发送消息
子线程:接收消息
作者:wjfree
使用:运行后发送消息:IP +空格+ Message
编译:linux 下:gcc ./chatlin.c -lpthread -o chat
win下:在lcc下添加工程,编译
*/
int main ()
... {
#ifdef WIN32
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD( 2, 2 );
int err = WSAStartup( wVersionRequested, &wsaData );
HANDLE hThread;
DWORD dwThreadId;
hThread= CreateThread(NULL,0, (LPTHREAD_START_ROUTINE)rcv,NULL,0,&dwThreadId);
snd();
WSACleanup();
#else
pthread_t id;
int ret;
ret = pthread_create(&id,NULL,(tc_thread_func)rcv,NULL); /**//*创建一个线程*/
snd();
#endif
return 0;
}
/**/ /*函数:snd()
功能:用scanf()函数接收ip地址和消息内容,发到对应的IP上
作者:wjfree
*/
void snd()
... {
struct sockaddr_in name;
int sock;
name.sin_family = PF_INET;
name.sin_port = htons(PORT);
sock = socket(PF_INET, SOCK_DGRAM,0);
if (sock < 0)
...{
printf("make socket error ");
return;
}
while(1)
...{
char bufloc[MAXBUF];
char ipaddr[17];
scanf("%s%s" , ipaddr, bufloc);
int i = name.sin_addr.s_addr = inet_addr(ipaddr);
if (i == -1)
...{
printf("IP address format error! ");
}
else
...{
int i = sendto(sock, bufloc, strlen(bufloc), 0, (struct sockaddr *)&name, sizeof(name));
if (i < 0)
printf("Can not send the message to %s ", ipaddr);
}
}
closesocket(sock);
}
/**/ /*函数:snd()
功能:接收消息并显示在终端
作者:wjfree
*/
void rcv()
... {
struct sockaddr_in RecvAddr;
struct sockaddr_in SenderAddr;
int sock;
sock = socket(AF_INET, SOCK_DGRAM, 0);
RecvAddr.sin_family = AF_INET;
RecvAddr.sin_port = htons(PORT);
RecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(sock, (struct sockaddr *) &RecvAddr, sizeof(RecvAddr));
printf("Receiving datagrams... ");
while(1)
...{
int size = sizeof(SenderAddr);
char RecvBuf[MAXBUF];
int BufLen = MAXBUF;
int i = recvfrom(sock,
RecvBuf,
BufLen,
0,
(struct sockaddr *)&SenderAddr,
(size_t*)&size);
RecvBuf[i] = 0;
printf("%s: %s ", inet_ntoa(SenderAddr.sin_addr),RecvBuf);
}
closesocket(sock);
}