实现一个基本的数据报套接字客户端/服务器通信程序,客户端和服务器按如下步骤交互:
(1)客户端向服务器发出日期时间请求字符串,如:%D %Y %A %T等。
(2)服务器从网络接收到日期时间请求字符串后,根据字符串格式生成对应的日期时间值返回给客户端。
-
/*
UPD服务器
说明:数据报服务器,用于接收来自数据报客户端发来的请求
注意:本程序通过命令行参数获取服务器的IP地址和端口
用法:./server ip port
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#define BUFSIZE 1024
static void bail(constchar *on_what)
{
fputs(strerror(errno),stderr);
fputs(": ",stderr);
fputs(on_what, stderr);
fputc('\n',stderr);
exit(1);
}
int main(int argc,char **argv)
{
long z;
int sockfd;
char *srvr_addr=NULL;
struct sockaddr_in server_addr;//服务器
struct sockaddr_in client_addr;//客户端
int portnumber;
char dgram[BUFSIZE];//应用接收缓冲
char dtfmt[BUFSIZE];//日期时间结果
time_t td; //当前日期和时间
struct tm tm; //日期时间值
//从命令行获得服务器
srvr_addr=argv[1];
if ((portnumber=atoi(argv[2]))<0)
{
fprintf(stderr,"port error");
exit(1);
}
//创建UPD套接字
sockfd=socket(AF_INET,SOCK_DGRAM,0);
if (sockfd==-1)
bail("socket()");
//创建UDP服务器地址
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(portnumber);
if (!inet_aton(srvr_addr, &server_addr.sin_addr))
bail("bad address...");
//绑定服务器UDP套接字到指定地址和端口
z=bind(sockfd, (structsockaddr *)&server_addr,sizeof(server_addr));
if (z==-1)
bail("bind()");
//主循环等待客户端请求
printf("server is waiting for client request.\n");
for (; ; )
{
socklen_t size=sizeof(client_addr);
z=recvfrom(sockfd,dgram, sizeof(dgram), 0, (structsockaddr *)&client_addr,&size);
if (z<0)
bail("recvfrom()");
//处理客户端请求
dgram[z]=0;
if (!strcasecmp(dgram,"QUIT"))
continue;
//获取当前日期和时间
time(&td);
tm=*localtime(&td);
//根据输入请求字符串格式产生结果字符串
strftime(dtfmt, sizeof(dtfmt), dgram, &tm);
//向客户端发回结果
z=sendto(sockfd, dtfmt, strlen(dtfmt), 0, (structsockaddr*)&client_addr,sizeof(client_addr));
if (z<0)
bail("sendto()");
}
close(sockfd);
return 0;
}
对于数据报服务器,因为没有连接的概念,所以服务器代码不像流试套接字服务器那样分为主进程和子进程,并且每个子进程独立为一个客户端提供服务,而是每收到一个数据报就立即进行处理,处理完后在接收下一个数据报进行同样的处理。
-
/*
UDP客户端
用法:./client ip port
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#define BUFSIZE 1024
static void bail(const char *on_what)
{
fputs(strerror(errno),stderr);
fputs(": ",stderr);
fputs(on_what, stderr);
fputc('\n',stderr);
exit(1);
}
int main(int argc,char **argv)
{
long z;
int sockfd;
char *srv_addr=NULL;
struct sockaddr_in server_addr;//服务器地址
struct sockaddr_in _addr;
int portnumber;
char dgram[BUFSIZE];
//从命令行获取服务器地址字符串
srv_addr=argv[1];
if((portnumber=atoi(argv[2]))<0)
{
fprintf(stderr,"error");
exit(1);
}
//创建服务器地址
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(portnumber);
if (!inet_aton(srv_addr, &server_addr.sin_addr))
bail("bad address");
//创建UDP套接字
sockfd=socket(AF_INET,SOCK_DGRAM,0);
if (sockfd==-1)
bail("socket()");
for (; ; )
{
fputs("\nEnter format string:",stdout);
if (!fgets(dgram,sizeof(dgram),stdin))
break;
z=strlen(dgram);
if (z>0 && dgram[--z]=='\n')
dgram[z]=0; //添加NULL结束标记
if(z==0)
continue;
//发送请求字符串
z=sendto(sockfd, dgram, strlen(dgram), 0, (struct sockaddr*)&server_addr,sizeof(server_addr));
if (z<0)
bail("sendto()");
printf("send over...ans dgram=%s\n",dgram);
//如果输入了退出命令‘quit’
if (!strcasecmp(dgram,"QUIT"))
break;
//等待服务器应答
socklen_t size=sizeof(_addr);
z=recvfrom(sockfd, dgram, sizeof(dgram), 0, (struct sockaddr*)&_addr, &size);
if (z<0)
bail("recvfrom()");
dgram[z]=0;
printf("result from %s port %u:\n\t '%s'\n",inet_ntoa(_addr.sin_addr),ntohs(_addr.sin_port),dgram);
}
printf("\n exits from loop.\n");
close(sockfd);
return 0;
}