首先明白,对于UDP而言,没有所谓的服务器端和客户端之分,言下之意,就是。。。。
这要写一个程序,就可以代表客户端又可以代表服务器
真这么牛。。。。。。还是看看再说吧!!!!
头文件
#include <sys/types.h>
#include <sys/socket.h>
函数原型
int sendto (int s, const void *buf, int len, unsigned int flags, const struct sockaddr *to, int tolen);
int recvfrom(int s, void *buf, int len, unsigned int flags, struct sockaddr *from, int *fromlen);
函数说明
sendto(): 是把UDP数据报发给指定地址;recvfrom(): 是从指定地址接收UDP数据报。
参数说明
s: socket描述符。buf: UDP数据报缓存地址。
len: UDP数据报长度。
flags: 该参数一般为0。
to: sendto()函数参数,struct sockaddr_in类型,指明UDP数据发往哪里报。
tolen: 对方地址长度,一般为:sizeof(struct sockaddr_in)。
fromlen: struct sockaddr_in类型,指明从哪里接收UDP数据报。
函数返回值
对于sendto()函数,成功则返回实际传送出去的字符数,失败返回-1,错误原因存于errno 中。对于recvfrom()函数,成功则返回接收到的字符数,失败则返回-1,错误原因存于errno中。
struct sockaddr_in结构体
该结构体的定义如下:
/* Structure describing an Internet (IP) socket address. */
#define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */
struct sockaddr_in {
sa_family_t sin_family; /* Address family */
__be16 sin_port; /* Port number */
struct in_addr sin_addr; /* Internet address */
/* Pad to size of `struct sockaddr'. */
unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) -
sizeof(unsigned short int) - sizeof(struct in_addr)];
};
其中,
sin_family: 指明地址族,一般使用AF_INET。
sin_port: 指明UDP端口。
sin_addr: 指明IP地址。
INADDR_ANY
INADDR_ANY是个特殊IP地址 ,表示任务的IP地址,作为服务器端的时候经常要用到。作为接收端,当你调用bind()函数绑定IP时使用INADDR_ANY,表明接收来自任意IP、任意网卡的发给指定端口的数据。作为发送端,当用调用bind()函数绑定IP时使用INADDR_ANY,表明使用网卡号最低的网卡进行发送数据,也就是UDP数据广播。关于UDP数据报UDP都是以数据报的形式进行发送和接收的,而TCP是以数据流的形式进行发送和接收的。数据报和数据流,这两者要区分开来。
上面这段话就是说,当你使用多网卡时,每个网卡都有不同的ip,如果你的绑定操作就要针对每个网卡都进行,否则数据就可能得不到处理。现在,INADDR_ANY出现了(其实它就等于0),它允许你就所有网卡看成一个使用,这个网卡的ip就是INADDR_ANY
好吧,我承认我有罪,上面纯属意外,如有雷同,属于我抄袭你
被废话了,进入正题:
具体使用
发送数据:
1.创建socket
int cfd = socket(AF_INET,SOCK_DGRAM,0);
2.发送数据
struct sockaddr_in si_recver; //接收方的地址
int addrlen = sizeof(si_recver);
bzero(&si_recver,addrlen);
si_recver.sin_family = AF_INET;
si_recver.sin_port = htons(7000);
si_recver.sin_addr.s_addr = INADDR_ANY;
sendto(cfd,buffer,buffer_size,0,(struct sockaddr *)&si_recver,addrlen);
哈哈,你肯定想说,怎么不绑定一下,呵呵,原来如果你没有绑定,sendto函数内部会替你绑定
接受数据:
1.创建socket
int cfd = socket(AF_INET,SOCK_DGRAM,0);
2.绑定端口和ip地址
struct sockaddr_in si;
int addrlen = sizeof(si);
bzero(&si,addrlen);si.sin_family = AF_INET;
si.sin_port = htons(7500);
si.sin_addr.s_addr = INADDR_ANY;
bind(cfd, (struct sockaddr *)&si, sizeof(si));
3.接受数据
recvfrom(cfd, buffer, buffer_size, 0, (struct sockaddr*)&si_recver, &addrlen);
好了,到此,全部工作已经完成






#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <poll.h>
#define MAX_RECEIVE_BUFFER 128
int main(int argc,char *argv[])
{
if (argc != 3)
return -1;
//1.创建通讯套接字
int cfd = socket(AF_INET,SOCK_DGRAM,0);
if (cfd < 0)
{
perror("socket");
return 0;
}
//寻址,这里寻找的地址是用来绑定自己
struct sockaddr_in si;
int ret;
si.sin_family = AF_INET;
si.sin_port = htons(atoi(argv[1]));
si.sin_addr.s_addr = INADDR_ANY;
//2.绑定
ret = bind(cfd, (struct sockaddr *)&si, sizeof(si));
if(ret == -1)
{
perror("bind");
return -1;
}
// 寻址,这里寻的址是要发送给对方的地址
//int n = 1; //这个值用来控制下面设置属性的开关,0表示关,非0启用
//setsockopt(cfd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(int));
struct sockaddr_in si_recver; //接收方的地址
int addrlen = sizeof(si_recver);
bzero(&si_recver,addrlen);
si_recver.sin_family = AF_INET;
si_recver.sin_port = htons(atoi(argv[2]));
si_recver.sin_addr.s_addr = INADDR_ANY;
// 收/发
int len;
char buf[MAX_RECEIVE_BUFFER];
struct pollfd arr[2];
arr[0].fd = 0;//输入设备
arr[0].events = POLLIN;
arr[1].fd = cfd;//socket
arr[1].events = POLLIN;
while(1)
{
poll(arr,2,-1);
if (arr[0].revents == POLLIN)
{
bzero(buf,MAX_RECEIVE_BUFFER);
read(0,buf,MAX_RECEIVE_BUFFER);
sendto(cfd, buf, MAX_RECEIVE_BUFFER-1, 0, (struct sockaddr *)&si_recver, addrlen);
}
if (arr[1].revents == POLLIN)
{
recvfrom(cfd, buf, MAX_RECEIVE_BUFFER, 0, (struct sockaddr*)&si_recver, &addrlen);
printf("[%s:%d]:%s\n",(char *)inet_ntoa(si_recver.sin_addr),si_recver.sin_port,buf);
}
}
// 4.关闭套接字
close(cfd);
return 0;
}