昨天转了篇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()函数后,直接用套接字读和写就可以。