d) 服务器端发送消息输入消息并回车即可发送。
注意:由于程序顺序/循环执行,非事件驱动结构,因此必须在接收到对方发送的数据后,己方方可发送。
3、 UDP通信1. UDP简介UDP是无连接的不可靠的传输协议。采用UDP进行通信时,不需要建立连接,可以直接向一个IP地址发送数据,但是不能保证对方能收到。
对于基于UDP面向无连接的套接字编程来说,服务器端和客户端这种概念不是特别的严格。可以把服务器端称为接收端,客户端就是发送数据的发送端。
2. UDP通信过程图 20
服务器端先初始化Socket,然后与端口绑定(bind),在这时如果有个客户端初始化一个Socket,客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,一次交互结束。
注意到,在进行端口绑定(bind)之后,服务器端不需要对端口进行监听(listen),也不需要调用等待连接(accept)阻塞,等待客户端连接。而客户端无需使用连接(connect)事先与服务器建立连接。
3. UDP服务器程序流程- 建立套接字文件描述符,使用函数socket(),生成套接字文件描述符。
- 设置服务器地址和侦听端口,初始化要绑定的网络地址结构。
- 绑定侦听端口,使用bind()函数,将套接字文件描述符和一个地址类型变量进行绑定。
- 接收客户端的数据,使用recvfrom()函数接收客户端的网络数据。
- 向客户端发送数据,使用sendto()函数向服务器主机发送数据。
- 关闭套接字,使用close()函数释放资源。UDP协议的客户端流程.
4. UDP客户端程序流程- 建立套接字文件描述符,socket()。
- 设置服务器地址和端口,struct sockaddr。
- 向服务器发送数据,sendto()。
- 接收服务器的数据,recvfrom()。
- 关闭套接字,close()。
5. 通信实验1) 实验内容说明本次实验进行了更为简单的验证次实验启动服务器后监听某端口后,由客户端发送一固定数据给服务器,服务器接收并显示后。双方释放套接字并结束程序。
2) 服务器端程序的编制a) 程序变量定义及函数声明b) 程序主函数c) 其他子函数其他子函数包括用于初始化套接字,绑定IP和端口的函数,其中分别调用了Socket中提供的功能函数。其具体实现由附件5给出。
3) 客户端程序的编制a) 程序变量定义及函数声明b) 程序主函数c) 其他子函数其他子函数包括用于初始化套接字,设置服务器IP和端口的函数,其中分别调用了Socket中提供的功能函数。其具体实现由附件6给出。
4) 实验过程a) 启动服务器并监听端口b) 启动客户端向服务器发送c) 服务器接收并显示
图 21
图 22
5. 附件五(UDP Server程序)
#include<stdio.h>
#include<winsock.h> /*引入winsock头文件*/
#pragma comment(lib,"ws2_32.lib")
char Receivebuf[100]; /*接受数据的缓冲区*/
int length;
SOCKET socket_send; /*定义套接字*/
SOCKADDR_IN Server_add; /*服务器地址信息结构*/
SOCKADDR_IN Client_add; /*客户端地址信息结构*/
WORD wVersionRequested; /*字(word):unsigned short*/
WSADATA wsaData; /*库版本信息结构*/
int error; /*表示错误*/
void Init_Socket(); /*初始化套接字*/
void Bind_Socket(); /*绑定套接字*/
int main()
{
memset(Receivebuf,0,100); /*清空接收缓冲*/
Init_Socket(); /*初始化套接字*/
socket_send=socket(AF_INET,SOCK_DGRAM,0); /*创建套接字*/
Bind_Socket(); /*绑定套接字*/
recvfrom(socket_send,Receivebuf,100,0,(SOCKADDR*)&Client_add,&length);
printf("客户端:%s\n",Receivebuf); /*接收并显示数据*/
closesocket(socket_send); /*释放套接字资源*/
WSACleanup(); /*关闭动态链接库*/
system("pause");
return 0;
}
void Init_Socket()
{
/*-------------------------初始化套接字库---------------------------*/
/*定义版本类型。将两个字节组合成一个字,前面是第字节,后面是高字节*/
wVersionRequested = MAKEWORD( 2, 2 );
/*加载套接字库,初始化Ws2_32.dll动态链接库*/
error = WSAStartup( wVersionRequested, &wsaData);
if(error!=0)
{
printf("加载套接字失败!\n");
return 0; /*程序结束*/
}
/*判断请求加载的版本号是否符合要求*/
if (LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2)
{
WSACleanup( ); /*不符合,关闭套接字库*/
return 0; /*程序结束*/
}
printf("加载套接字成功。\n");
}
void Bind_Socket()
{
/*----------------------设置服务器地址-----------------------*/
Server_add.sin_family=AF_INET;/*地址家族,对于必须是AF_INET,注意只有它不是网络网络字节顺序*/
Server_add.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
Server_add.sin_port=htons(5000);/*端口号*/
/*绑定套接字*/
bind(socket_send,(SOCKADDR*)&Server_add,sizeof(SOCKADDR));
length=sizeof(SOCKADDR);
printf("绑定成功。\n正在监听\n");
}
6. 附件六(UDP Client程序)
#include<stdio.h>
#include<winsock.h> /*引入winsock头文件*/
#pragma comment(lib,"ws2_32.lib")
#define Msg "This is a test!" /*待发送数据*/
SOCKET socket_client; /*定义套接字*/
SOCKADDR_IN Server_add; /*服务器地址信息结构*/
WORD wVersionRequested; /*字(word):unsigned short*/
WSADATA wsaData; /*库版本信息结构*/
int error; /*表示错误*/
void Init_Socket(); /*初始化套接字*/
void Set_Server(); /*设置服务器地址和端口*/
int main()
{
Init_Socket(); /*初始化套接字*/
socket_client=socket(AF_INET,SOCK_DGRAM,0); /*创建套接字*/
Set_Server(); /*设置服务器地址和端口*/
/*发送数据*/
sendto(socket_client,Msg,strlen(Msg)+1,0,(SOCKADDR*)&Server_add,sizeof(SOCKADDR));
printf("已发送数据至服务器\n");
closesocket(socket_client); /*释放套接字资源*/
WSACleanup(); /*关闭动态链接库*/
system("pause");
return 0;
}
void Init_Socket()
{
/*-------------------------初始化套接字库---------------------------*/
/*定义版本类型。将两个字节组合成一个字,前面是第字节,后面是高字节*/
wVersionRequested = MAKEWORD( 2, 2 );
/*加载套接字库,初始化Ws2_32.dll动态链接库*/
error = WSAStartup( wVersionRequested, &wsaData);
if(error!=0)
{
printf("加载套接字失败!\n");
return 0; /*程序结束*/
}
/*判断请求加载的版本号是否符合要求*/
if ( LOBYTE( wsaData.wVersion ) != 2 ||
HIBYTE( wsaData.wVersion ) != 2 )
{
WSACleanup( ); /*不符合,关闭套接字库*/
return 0; /*程序结束*/
}
printf("加载套接字成功。\n");
}
void Set_Server()
{
/*----------------------设置服务器地址-----------------------*/
Server_add.sin_family=AF_INET;/*地址家族,对于必须是AF_INET,注意只有它不是网络网络字节顺序*/
Server_add.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
Server_add.sin_port=htons(5000); /*端口号*/
printf("服务器设置成功。\n");
}
4. 附件四(TCP Client程序)
#include<stdio.h>
#include<winsock.h> /*引入winsock头文件*/
#pragma comment(lib,"ws2_32.lib")
char Sendbuf[100]; /*发送数据的缓冲区*/
char Receivebuf[100]; /*接受数据的缓冲区*/
int SendLen; /*发送数据的长度*/
int ReceiveLen; /*接收数据的长度*/
char IPaddress[16]; /*IP地址数组*/
char Port[6]; /*端口数组*/
SOCKET socket_send; /*定义套接字*/
SOCKADDR_IN Server_add; /*服务器地址信息结构*/
WORD wVersionRequested; /*字(word):unsigned short*/
WSADATA wsaData; /*库版本信息结构*/
int error; /*表示错误*/
int Init_Socket(); /*初始化套接字*/
void Create_Socket(); /*创建套接字*/
void Connect_Socket(); /*连接服务器*/
void Close_Socket(); /*释放套接字*/
int main()
{
Init_Socket(); /*初始化套接字*/
Create_Socket(); /*创建套接字*/
Connect_Socket(); /*连接服务器*/
while(1) /*具体通信过程*/
{
/*---------------发送数据过程----------*/
printf("请输入消息:");
gets(Sendbuf); //获取输入的数据
SendLen = send(socket_send,Sendbuf,100,0); //启动发送
if(SendLen < 0)
{
printf("发送失败!\n"); //发送失败
break;
}
/*--------------接收数据过程---------------*/
ReceiveLen =recv(socket_send,Receivebuf,100,0); //结束数据存缓冲区
if(ReceiveLen<0)
{
printf("连接关闭或接收失败\n程序退出\n"); //接收或连接失败
break;
}
else
{
printf("来自服务器:%s\n",Receivebuf); //显示收到的数据
}
}
Close_Socket(); /*释放套接字*/
return 0;
}
int Init_Socket()
{
/*------------初始化套接字库---------------*/
/*定义版本类型。将两个字节组合成一个字,前面是第字节,后面是高字节*/
wVersionRequested = MAKEWORD( 2, 2 );
/*加载套接字库,初始化Ws2_32.dll动态链接库*/
error = WSAStartup( wVersionRequested, &wsaData);
if(error!=0)
{
printf("加载套接字失败。\n");
return 0; /*程序结束*/
}
else
{
printf("加载套接字成功。\n");
}
/*判断请求加载的版本号是否符合要求*/
if(LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2)
{
WSACleanup( ); /*不符合,关闭套接字库*/
return 0; /*程序结束*/
}
else
{
printf("加载版本号符合。\n");
}
}
void Create_Socket()
{
/*-------------进行连接服务器--------------*/
/*客户端创建套接字,但是不需要绑定的,只需要和服务器建立起连接就可以了。*/
/*socket_sendr表示的是套接字,Server_add服务器的地址结构*/
socket_send=socket(AF_INET,SOCK_STREAM,0);
}
void Connect_Socket()
{
/*------------设置服务器地址---------------*/
Server_add.sin_family=AF_INET;/*地址家族,对于必须是AF_INET,注意只有它不是网络网络字节顺序*/
/*服务器的地址,将一个点分十进制表示为IP地址,inet_ntoa是将地址转成字符串*/
puts("输入IP地址:");
gets(IPaddress);
puts("输入端口:");
gets(Port);
Server_add.sin_addr.S_un.S_addr = inet_addr(IPaddress);
Server_add.sin_port=htons(atoi(Port)); /*端口号*/
/*-------------创建用于连接的套接字--------*/
/*AF_INET表示指定地址族,SOCK_STREAM表示流式套接字TCP,特定的地址家族相关的协议。*/
if(connect(socket_send,(SOCKADDR*)&Server_add,sizeof(SOCKADDR)) == SOCKET_ERROR)
{
printf("服务器连接失败。\n");
}
else
{
printf("服务器连接成功。\n");
}
}
void Close_Socket()
{
/*---------释放套接字,关闭动态库----------*/
closesocket(socket_send); /*释放套接字资源*/
WSACleanup(); /*关闭动态链接库*/
}
3. 附件三(TCP Server程序)
#include<stdio.h>
#include<winsock.h> /*引入winsock头文件*/
#pragma comment(lib,"ws2_32.lib")
#define IPaddress "127.0.0.1" /*IP地址*/
#define Port "5000" /*端口*/
char Sendbuf[100]; /*发送数据的缓冲区*/
char Receivebuf[100]; /*接受数据的缓冲区*/
int SendLen; /*发送数据的长度*/
int ReceiveLen; /*接收数据的长度*/
int Length; /*表示SOCKADDR的大小*/
SOCKET socket_server; /*定义服务器套接字*/
SOCKET socket_receive; /*定义用于连接套接字*/
SOCKADDR_IN Server_add; /*服务器地址信息结构*/
SOCKADDR_IN Client_add; /*客户端地址信息结构*/
WORD wVersionRequested; /*字(word):unsigned short*/
WSADATA wsaData; /*库版本信息结构*/
int error; /*表示错误*/
int Init_Socket(); /*初始化套接字*/
void Create_Socket(); /*创建套接字*/
int Bind_Socket(); /*绑定IP和端口*/
int Listen_Socket(); /*设置监听状态*/
int Wait_Socket(); /*等待客户端连接*/
void Close_Socket(); /*释放套接字*/
int main()
{
Init_Socket(); /*初始化套接字*/
Create_Socket(); /*创建套接字*/
Bind_Socket(); /*绑定IP和端口*/
Listen_Socket(); /*设置监听状态*/
Wait_Socket(); /*等待客户端连接*/
while(1) /*具体通信过程*/
{
/*--------接收数据---------*/
ReceiveLen =recv(socket_receive,Receivebuf,100,0); //接收数据存缓冲区
if(ReceiveLen<0) //连接或接收失败
{
printf("客户端中断连接或接收失败\n程序退出\n");
break;
}
else
{
printf("来自客户端:%s\n",Receivebuf); //显示接收到的数据
}
/*--------发送数据---------*/
printf("请输入消息:");
gets(Sendbuf); //获取输入的数据
SendLen=send(socket_receive,Sendbuf,100,0); //启动发送
if(SendLen<0)
{
printf("发送失败。\n"); //本次发送失败
break;
}
}
Close_Socket(); /*释放连接*/
return 0;
}
int Init_Socket()
{
/*------------初始化套接字库---------------*/
/*定义版本类型。将两个字节组合成一个字,前面是第字节,后面是高字节*/
wVersionRequested = MAKEWORD( 2, 2 );
/*加载套接字库,初始化Ws2_32.dll动态链接库*/
error = WSAStartup( wVersionRequested, &wsaData);
if(error!=0)
{
printf("加载套接字失败。\n");
return 0; /*程序结束*/
}
else
{
printf("加载套接字成功。\n");
}
/*判断请求加载的版本号是否符合要求*/
if(LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2)
{
WSACleanup( ); /*不符合,关闭套接字库*/
return 0; /*程序结束*/
}
else
{
printf("加载版本号符合。\n");
}
return 1;
}
void Create_Socket()
{
/*------------设置连接地址-----------------*/
Server_add.sin_family=AF_INET;/*地址家族,对于必须是AF_INET,注意只有它不是网络网络字节顺序*/
Server_add.sin_addr.S_un.S_addr=inet_addr(IPaddress); /*主机地址*/
Server_add.sin_port=htons(atoi(Port));/*端口号*/
/*------------创建套接字-------------------*/
/*AF_INET表示指定地址族,SOCK_STREAM表示流式套接字TCP,特定的地址家族相关的协议。*/
socket_server=socket(AF_INET,SOCK_STREAM,0);
}
int Bind_Socket()
{
/*---绑定套接字到本地的某个地址和端口上----*/
/*socket_server为套接字,(SOCKADDR*)&Server_add为服务器地址*/
if(bind(socket_server,(SOCKADDR*)&Server_add,sizeof(SOCKADDR) )==SOCKET_ERROR)
{
printf("绑定失败。\n");
return 0;
}
else
{
printf("套接字绑定成功。\n");
printf("当前主机地址:");
printf(IPaddress);
printf("\n当前主机端口:");
printf(Port);
printf("\n");
}
return 1;
}
int Listen_Socket()
{
/*------------设置套接字为监听状态---------*/
/*监听状态,为连接做准备,最大等待的数目为5*/
if(listen(socket_server,5)<0)
{
printf("监听失败\n");
return 0;
}
else
{
printf("监听成功\n");
return 1;
}
}
int Wait_Socket()
{
/*------------接受连接---------------------*/
Length=sizeof(SOCKADDR);
/*接受客户端的发送请求,等待客户端发送connect请求*/
socket_receive=accept(socket_server,(SOCKADDR*)&Client_add,&Length);
if(socket_receive==SOCKET_ERROR)
{
printf("客户端连接失败。");
return 0;
}
else
{
printf("客户端连接成功。\n");
return 1;
}
}
void Close_Socket()
{
/*---------释放套接字,关闭动态库----------*/
closesocket(socket_receive); /*释放客户端的套接字资源*/
closesocket(socket_server); /*释放套接字资源*/
WSACleanup(); /*关闭动态链接库*/
}
7. 附件七(单片机原理图)