与TCP的不同
使用TCP套接口必须先要建立连接,而UDP套接口不需要预先建立连接,它在调用socket()生成一个套接口后,在服务器端调用bind()绑定端口,服务器阻塞于recvfrom()调用,客户端调用sendto()发送数据请求,阻塞于recvfrom()调用,服务器端调用recvfrom()接受数据,服务器端额调用sendto()向客户发送数据作为应答,然后阻塞于recvfrom()调用,客户端调用recvfrom()接收数据。
主要系统调用
函数(1):int recvfrom(int sockfd,void *buf,int len,inf flags,struct sockaddr *fromaddr,
socketlen_t *addrlen);
头文件:sys/socket.h
说明:函数返回实际读取的字节数,可以为0,错误返回-1。
函数(2):int sendto(int sockfd,void *buf,int len,int flag,struct sockaddr *toaddr,
socklen_t addrlen);
头文件:sys/socket.h
说明:函数返回实际写入段字节数,可以为0,出差返回-1。
UDP编程注意
由于UDP是无连接,不可靠的协议,没有TCP那样有重传确认的机制,因此在UDP编程中要注意数据可靠性的问题,主要包括:数据包的丢失,服务器进程未启动,数据源的可靠性等。
数据包的丢失可以采用设置一个定时器使用超时重传并使用序列号的可靠性机制等;数据源的可靠性,可以在客户端对数据源进行校验的机制等。
测试示例
服务端测试代码
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <netdb.h>
#include <stdarg.h>
#include <string.h>
#define MYPORT 4950
#define MAXSIZE 80
void str_ser(int sockfd);
int main(void)
{
int sockfd;
struct sockaddr_in my_addr;
struct sockaddr_in their_addr;
int addr_len;
if((sockfd=socket(AF_INET,SOCK_DGRAM,0))==-1){
printf("error in socket\n");
exit(1);
}
my_addr.sin_family=AF_INET;
my_addr.sin_port=htons(MYPORT);
my_addr.sin_addr.s_addr=htonl(INADDR_ANY);
memset(my_addr.sin_zero,0,8);
if(bind(sockfd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr))==-1){
printf("error in binding\n");
exit(1);
}
str_ser1(sockfd);
close(sockfd);
exit(1);
}
void str_ser(int sockfd)
{
char recvs[MAXSIZE];
int n=0,len;
struct sockaddr addr;
while(1){
len=sizeof(struct sockaddr_in);
printf("waiting for data...\n");
if((n=recvfrom(sockfd,recvs,MAXSIZE,0,(struct sockaddr *)&addr,&len))==-1){
printf("error receiving\n");
exit(1);
}
*(recvs+n-1)=0x00;
printf("Received [%s],return to client immediately\n",recvs);
strcpy(recvs,"ok");
sendto(sockfd,recvs,n,0,(struct sockaddr *)&addr,len);
}
}
客户端测试代码:
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <netdb.h>
#include <stdarg.h>
#include <string.h>
#define MYPORT 4950
#define MAXSIZE 80
void str_cli(FILE *fp,int sockfd, struct sockaddr *addr,int addrlen);
int main(int argc,char * argv[])
{
int sockfd,ret,len;
struct sockaddr_in their_addr;
char *myname;
struct in_addr **addrs;
struct hostent *sh;
if(argc!=2){
printf("parameters not match\n");
exit(0);
}
if((sh=gethostbyname(argv[1]))==NULL){
printf("ERROR when gethostby name\n");
exit(0);
}
sockfd=socket(AF_INET,SOCK_DGRAM,0);
if(sockfd<0){
printf("error in socket\n");
exit(1);
}
their_addr.sin_family=AF_INET;
their_addr.sin_port=htons(MYPORT);
their_addr.sin_addr=*((struct in_addr *)sh->h_addr);
memset(their_addr.sin_zero,0,8);
connect(sockfd,(struct sockaddr*)&their_addr,sizeof(struct sockaddr));
str_cli(stdin,sockfd,(struct sockaddr *)&their_addr,sizeof(struct sockaddr_in));
close(sockfd);
exit(0);
}
void str_cli(FILE *fp,int sockfd,struct sockaddr * addr,int addrlen)
{
char sends[MAXSIZE],recvs[MAXSIZE];
int len,n=0;
struct sockaddr *reply;
while(fgets(sends,MAXSIZE,fp)!=NULL){
sendto(sockfd,sends,strlen(sends),0,addr,addrlen);
len=addrlen;
n=recvfrom(sockfd,recvs,MAXSIZE,0,reply,&len);
if(n==-1){
printf("error receiving data\n");
exit(1);
}
if((len==addrlen)&& (memcmp(addr,reply,len)!=0)){
printf("message igored\n");
continue;
}
recvs[n]=0x00;
fputs(recvs,stdout);
}