昨天转了篇Linux下面向连接的UDP通信,想做个实验,看看是否能实现“面向连接”
实验结果表明是:UDP即便使用了connect()函数进行连接,传输失败仍然不会有任何的提示。
实验步骤如下
服务器端:
1. 建立套接字;
2. 绑定套接字;
3. 用recvfrom()、sendto() 函数进行信息的收发;
4. 关闭套接字;
客户端:
1. 建立套接字;
2. 向服务器端发送消息;
3. 接收服务器端回送的消息;
4. 关闭套接字;
注意:使用UDP通信时,客户端并没有显式的调用套接字绑定,但是默认建立好套接字后,如果首先使用sendto()函数,系统会自动实现套接字的绑定。
程序代码如下
共同代码:
初始化套接字类:
头文件
#include <winsock2.h>
class CinitSock
{
public:
CinitSock();
virtual ~CinitSock();
};
实现文件
CinitSock::CinitSock()
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 2, 2 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err )
{
printf("Ws2_32.lib加载出错");
return;
}
if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 )
{
printf("Ws2_32.dll加载时版本不匹配,您的机器可能不支持socket2.2版本");
WSACleanup( );
return;
}
}
CinitSock::~CinitSock()
{
WSACleanup();
}
服务器端:
#include "initSock.h"
#include <stdio.h>
void main()
{
CinitSock oinitSock;
SOCKET srvSock=socket(AF_INET, SOCK_DGRAM, 0);
int addrLen=sizeof(SOCKADDR);
//设置服务器的套接字
SOCKADDR_IN srvSockAddr;
srvSockAddr.sin_family=AF_INET;
srvSockAddr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
//srvSockAddr.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
srvSockAddr.sin_port=htons(2030);
//printf("服务器IP地址:%d", INADDR_ANY);
if(bind(srvSock, (SOCKADDR *)&srvSockAddr, addrLen))
{
printf("绑定出错\n");
return;
}
printf("服务器在127.0.0.1,端口2030上进行监听\n");
char recvBuf[128]={0};
//信息源套接字
SOCKADDR_IN clientSockAddr;
while(1)
{
if(recvfrom(srvSock, recvBuf, 128, 0, (SOCKADDR *)&clientSockAddr, &addrLen)>0)
{
printf("接收到数据%s\n", recvBuf);
char sendBuf[128]={0};
memcpy(sendBuf, "client, i love u", 128);
if(sendto(srvSock, sendBuf, 128, 0, (SOCKADDR *)&clientSockAddr, addrLen)>0)
printf("向客户端发送%s\n", recvBuf);
else
{
printf("向客户端发送信息失败\n");
return;
}
break;
}
}
closesocket(srvSock);
}
客户端代码:
#include <stdio.h>
#include "initSock.h"
void main()
{
CinitSock oinitSock;
SOCKET clientSock=socket(AF_INET, SOCK_DGRAM, 0);
char sendMsg[128]={0};
memcpy(sendMsg, "server, i love u", strlen("server, i love u"));
//设置目的套接字地址
SOCKADDR_IN sockaddrTo;
sockaddrTo.sin_family=AF_INET;
sockaddrTo.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
//sockaddrTo.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
sockaddrTo.sin_port=htons(2030);
int addrLen=sizeof(SOCKADDR);
if(connect(clientSock, (SOCKADDR *)&sockaddrTo, addrLen)==SOCKET_ERROR)
{
printf("连接服务器的时候出错\n");
return;
}
if(sendto(clientSock, sendMsg, strlen(sendMsg), 0, (SOCKADDR *)&sockaddrTo, addrLen)==SOCKET_ERROR)
{
printf("发送信息失败\n");
return;
}
char recvMsg[128];
while(1)
{
if(recvfrom(clientSock, recvMsg, strlen(recvMsg), 0, (SOCKADDR *)&sockaddrTo, &addrLen)>0)
{
printf("接收到数据:%s\n", recvMsg);
break;
}
}
closesocket(clientSock);
}
注意:INADDR_ANY就是指定地址为0.0.0.0的地址,这个地址事实上表示不确定地址,或“所有地址”、“任意地址”。 一般来说,在各个系统中均定义成为0值。
在服务器端可以使用INADDR_ANY进行ip设置,但在客户端发送消息时,必须指定服务器IP,不能使用INADDR_ANY
实验结果
客户端包括connect()函数和sendto()函数,连接失败或发送失败,根本没有提示。
而且,在windows下也没有linux中的read()和write()函数(连接错误之后系统会给客户端一个连接错误信息),其原因可能是因为linux系统下任何东西都可以看成是文件,在调用connect()函数后,直接用套接字读和写就可以。