基本UDP套接字编程
UDP函数调用为:客户不与服务器建立连接,而是只管使用sendto函数给服务器发送数据报,其中必须指定目的地的地址为参数。类似地,服务器不接受来客户的连接,而是只管调用recvfrom函数,等待来自某个客户的数据到达,recvfrom将与所接收的数据一道返回客户的协议地址,因此可以把响应发送给正确的客户。
recvfrom和sendto函数
这两个函数类似于标准的read和write函数,不过需要三个额外的参数
#included<sys/socket.h>
ssize_t recvfrom(int sockfd, void *buff, size_t nbytes, int flags,
struct sockaddr *from, socklen_t &addrlen);
ssize_t sendto(int sockfd, const void *buff, size_t nbytes, int flags,
const struct sockaddr * to, socklen_t *addrlen);
若成功则返回为读或写的字节数,若出错则为-1
前三个参数sockfd、buff和nbytes等同于read和write函数的三个参数:描述符、指读入或写出缓冲区的指针和读写字节数。
flags参数将在讨论recv、send、recvmsg和sendmsg等函数数再介绍,当前我们把flags置为0
sendto的to参数指向一个含有数据报接收者的协议地址(例如IP地址及端口号)的套接字地址结构,其大小由addrlen参数指定。recvfrom的from参数指向一个将由该函数在返回时填写数据报发送者的协议地址的套接字地址结构,而套接字地址结构中的字节数则放在addrlen参数所指的整数中返回给调用者。
UDP回射服务器程序
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
void dg_echo(int sockfd, struct sockaddr *pcliaddr, socklen_t clilen);
int main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr, cliaddr;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sockfd == -1)
{
printf("socket fail\n");
return -1;
}
bzero(&servaddr, sizeof(servaddr));//清空套接字地址结构
servaddr.sin_family = AF_INET;//指定协议
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//指定地址IP
servaddr.sin_port = htons(9988);//指定端口
int bindfd = bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
if(bindfd == -1)
{
printf("bind fail\n");
return -1;
}
dg_echo(sockfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr));
}
void dg_echo(int sockfd, struct sockaddr *pcliaddr, socklen_t clilen)
{
int n;
socklen_t len;
char mesg[2048];
for(;;)
{
len = clilen;
n = recvfrom(sockfd, mesg, 2048, 0, pcliaddr, &len);
if(n == -1)
{
printf("recvfrom fail\n");
return;
}
int s = sendto(sockfd, mesg, n, 0, pcliaddr, len);
if(s == -1)
{
printf("sendto fail\n");
return;
}
}
}
UDP客户端回射程序
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
void dg_cli(FILE *fp, int sockfd, const struct sockaddr *pservaddr, socklen_t servlen);
int main(int argc, char *argv[])
{
int sockfd;
struct sockaddr_in servaddr;
if(argc != 2)
{
printf("iusage:udpcli<IPaddress>");
return -1;
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(9988);
inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
dg_cli(stdin, sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
exit(0);
}
void dg_cli(FILE *fp, int sockfd, const struct sockaddr *pservaddr, socklen_t servlen)
{
int n;
char sendline[2048], recvline[2049];
while(fgets(sendline, 2048, fp) != NULL)
{
int s = sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);
if(s == -1)
{
printf("sendto fail\n");
return;
}
n = recvfrom(sockfd, recvline, 2048, 0, NULL, NULL);
if(n == -1)
{
printf("recvfrom fail\n");
return;
}
recvline[n] = 0;
fputs(recvline, stdout);
}
}