在Linux学习之旅(27)---套接字编程基础知识讲述了套接字编程的一些基础知识和C/S模型(TCP)。在运输层有两个协议面向连接的TCP和无连接的UDP。在这一张我们将讲述C/S模型如何使用UDP实现。关于UDP的特点可以通过Linux学习之旅(25)-----网络协议来了解。
UDP编程框架
1、UDP编程框架图
在UDP编程的框架模型中,没有connect(),listen()和accept()函数,这是由于UDP协议无连接的特性决定的。
2、函数说明
(1)socket():创建套接字
(2)bind():绑定套接字,这两个函数和TCP中的使用方法是相同的。
(3)recvfrom()和recv():接收数据
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int s,void* buf,size_t len,int flags);
ssize_t recvfrom(int s void* buf,size_t len,int flags,struct sockaddr* from ,socklen_t* fromlen);
参数说明:
s:表示正在监听的套接字的文件描述符。
buf:表示接收数据缓冲区,接收到的数据将放在这个指针所指向的空间中。
len:表示数据缓冲区额度大小,系统根据这个值来确保接收区的安全,防止溢出。
flags:默认为0。
from:传出参数,发送方的端口信息。
fromlen:传入传出参数,表示from参数的长度。
返回值:成功返回数据长度,失败返回-1。当返回值为0时,表示系统此时接收不到数据。
(4)send()和sendto():接收数据
#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int s,const void* buf,size_t len,int flags);
ssize_t sendto(int s ,const void* buf,size_t len,int flags,const struct sockaddr* to ,socklen_t tolen);
参数说明:
s:正在监听的套接字端口。
buf:发送数据缓冲区,发送的数据放在此指针指向的内存空间中。
len:发送数据缓冲区的大小。
to:目的主机的端口。
tolen:目的主机的端口长度。
返回值:成功返回数据长度,失败返回-1。数据长度可以为0。
程序1、UDP服务器端
服务器功能:将客户端发送的数据中的小写字母转化成大写字符,并返回给发送端。
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define PORT 5500
#define BUFSIZE 1024
int main()
{
//创建一个使用ipv4和默认协议的数据报套接字
int serSock=socket(AF_INET,SOCK_DGRAM,0);
struct sockaddr_in serAddr;
//将端口信息清零
bzero(&serAddr,sizeof(serAddr));
serAddr.sin_family=AF_INET;
//INADDR_ANY的值为0,表示本机的所有端口
serAddr.sin_addr.s_addr=htonl(INADDR_ANY);
//设置端口号
serAddr.sin_port=htons(5500);
//绑定套接字和端口信息
bind(serSock,(struct sockaddr *)(&serAddr),sizeof(serAddr));
char dataBuf[BUFSIZE];
bzero(dataBuf,BUFSIZE);
printf("UDP SERVER RECVING.....\n");
while(1)
{
struct sockaddr_in cliAddr;
bzero(&cliAddr,sizeof(cliAddr));
socklen_t cliAddrLen=sizeof(cliAddr);
//接收客户端发送的数据
ssize_t datalen=recvfrom(serSock,(void *)dataBuf,BUFSIZE,0,(struct sockaddr*)(&cliAddr),&cliAddrLen);
//打印客户端的IP和端口号
char cliStrIP[32];
printf("Client IP:%s",inet_ntop(AF_INET,&(cliAddr.sin_addr.s_addr),cliStrIP,sizeof(cliStrIP)));
printf("client prot:%d\n",ntohs(cliAddr.sin_port));
//数据处理
int i=0;
while(i<datalen)
{
dataBuf[i]=toupper(dataBuf[i]);
++i;
}
//向客户端发送数据
sendto(serSock,(void *)dataBuf,datalen,0,(struct sockaddr*)(&cliAddr),sizeof(cliAddr));
}
//关闭套接字
close(serSock);
return 0;
}
程序2、UDP客户端
客户端功能:向服务器发送给消息并将服务器回送的消息显示出来。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 5500
#define BUFSIZE 1024
int main(int argc,char* argv[])
{
if(argc<2)
{
printf("CLIENT IPADDRESS\n");
exit(1);
}
//创建一个使用IPV4和默认协议的数据报套接字
int cliSock=socket(AF_INET,SOCK_DGRAM,0);
struct sockaddr_in serAddr;
bzero(&serAddr,sizeof(serAddr));
serAddr.sin_family=AF_INET;
inet_pton(AF_INET,argv[1],&(serAddr.sin_addr));
serAddr.sin_port=htons(PORT);
while(1)
{
char dataBuf[BUFSIZE];
int serAddrLen=sizeof(serAddr);
scanf("%s",dataBuf);
sendto(cliSock,(void*)dataBuf,strlen(dataBuf),0,(struct sockaddr*)(&serAddr),sizeof(serAddr));
recvfrom(cliSock,(void*)dataBuf,BUFSIZE,0,(struct sockaddr*)(&serAddr),&serAddrLen);
printf("%s",dataBuf);
}
close(cliSock);
return 0;
}
nc命令
nc时netcat的简写,被誉为网络界的瑞士军刀。因为它短小精悍,功能实用。它的作用有以下几个:
(1)实现任意TCP/UDP端口的监听(服务器)。
(2)端口的扫描,nc可以作为client发起TCP/UDP连接(客户端)。
(3)机器之间传输文件。
(4)机器之间网络测速。
nv -[lpsuvwz]
参数说明:
(1)-l:将nc作为服务器,监听并接收连接。
(2)-p:端口号。
(3)-s:指定发送数据的源IP地址,适用于多网卡机。
(4)-u:使用UDP协议,默认为TCP。
(5)-v:输出交互或出错信息。
(6)-w:超时秒数。
(7)-z:表示0,即扫描时不发送数据。