1.UDP套接字编程过程
图1 UDP客户端/服务器端
sendto 与 recvfrom 函数
这两个函数的功能类似于 write 和 read 函数,可用无连接的套接字编程。其定义如下:
/* 函数功能:发送数据;
* 返回值:若成功则返回已发送的字节数,若出错则返回-1;
* 函数原型:
*/
#include <sys/socket.h>
#include <sys/types.h>
ssize_t sendto(int sockfd, void *buff, size_t nbytes, int flags,
const struct sockaddr *destaddr, socklen_t addrlen);
/* 说明:
* 该函数功能类似于write函数,除了有标识符flags和目的地址信息之外,其他参数一样;
*
* flags标识符取值如下:
* (1)MSG_DONTROUTE 勿将数据路由出本地网络
* (2)MSG_DONTWAIT 允许非阻塞操作
* (3)MSG_EOR 如果协议支持,此为记录结束
* (4)MSG_OOB 如果协议支持,发送带外数据
*
* 若sendto成功,则只是表示已将数据无错误的发送到网络,并不能保证正确到达对端;
* 该函数通过指定目标地址允许在无连接的套接字之间发送数据(例如UDP套接字);
*/
/* 函数功能:接收数据;
* 返回值:以字节计数的消息长度,若无可用消息或对方已经按序结束则返回0,若出错则返回-1;
* 函数原型:
*/
#include <sys/socket.h>
#include <sys/types.h>
ssize_t recvfrom(int sockfd, void *buff, size_t nbytes, int flags,
struct sockaddr *addr, socklen_t *addrlen);
/* 说明:
* 该函数功能与read类似;
* 若addr为非空时,它将包含数据发送者的套接字地址;
*
* flags标识符取值如下:
* (1)MSG_WAITALL 等待所有数据可用
* (2)MSG_DONTWAIT 允许非阻塞操作
* (3)MSG_PEEK 查看已读取的数据
* (4)MSG_OOB 如果协议支持,发送带外数据
*/
基于 UDP 套接字编程
下面我们使用 UDP 协议实现简单的功能,客户端从标准输入读取数据并把它发送给服务器,服务器接收到数据并把该数据回射给客户端,然后客户端收到从服务器回射的数据把它显示到标准输出。其功能实现如下图所示:
UDP服务器端
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <unistd.h>
#include <errno.h>
int main(int argc, char* argv[])
{
if(argc != 3){
printf("Usage: %s [ip[ [port]\n", argv[0]);
return 1;
}
int sockfd = socket(AF_INET, SOCK_DGRAM, 0); //创建socket文件描述符,SOCK_DGRAM表示UDP
if(sockfd < 0){
perror("socket");
return 2;
}
struct sockaddr_in local; //给结构体另起一个名字
local.sin_family = AF_INET; //地址类型
local.sin_port = htons(atoi(argv[2])); //将端口号转换成网络字节序,16位,短整形
local.sin_addr.s_addr = inet_addr(argv[1]);
if(bind(sockfd,(struct sockaddr*)&local,sizeof(local)) < 0){
perror("bind");
return 3;
char buf[1024];
struct sockaddr_in client;
while(1){
socklen_t len = sizeof(client);
ssize_t s = recvfrom(sockfd, buf, sizeof(buf)-1,0, (struct sockaddr*)&client, &len);
if(s > 0){
buf[s] = 0;
printf("[%s,%d]: %s\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port), buf);
sendto(sockfd, buf, strlen(buf),0, (struct sockaddr*)&client, sizeof(client));
}
}
return 0;
}
客户端
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <errno.h>
int main(int argc, char* argv[])
{
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if(sock < 0){
perror("socket");
return 2;
}
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(atoi(argv[2]));
server.sin_addr.s_addr = inet_addr(argv[1]);
char buf[1024];
struct sockaddr_in peer;
while(1){
socklen_t len = sizeof(peer);
printf("Please Enter#: ");
fflush(stdout);
ssize_t s = read(0, buf, sizeof(buf)-1);
if(s > 0){
buf[s-1] = 0;
sendto(sock, buf, strlen(buf), 0, (struct sockaddr*)&server, sizeof(server));
ssize_t _s = recvfrom(sock, buf, sizeof(buf)-1, 0, (struct sockaddr*)&peer,&len);
if(s > 0){
buf[_s] = 0;
printf("service echo# %s\n", buf);
}
}
}
return 0;
}