服务端
1.创建套接字
int sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(sockfd == 0){
perror("socket error");
return -1;
}
2.为套接字绑定地址信息
//2.为套接字绑定地址信息
// int bind(套接字描述符, 地址信息, 地址长度)
struct sockaddr_in addr;//定义IPv4地址结构
addr.sin_family = AF_INET;
addr.sin_port = htons(9000);//设置地址端口
addr.sin_addr.s_addr = inet_addr("192.168.117.135");
int len = sizeof(addr);
int ret = bind(sockfd, (struct sockaddr*)&addr, len);
if(ret < 0){
perror("bind error");
return -1;
}
3.接收数据
//3.接收数据
// recvfrom(句柄, 空间, 长度, 标志, 对端地址, 地址长度)
char buf[1024] = {0};
struct sockaddr_in paddr;
int len = sizeof(struct sockaddr_in);
ret = recvfrom(sockfd, buf, 1023, 0, (struct sockaddr*)&paddr, &len);
if(ret < 0){
perror("recvfrom error");
return -1;
}
printf("client say: %s\n", buf);
4.回复数据
//4.回复数据
// int sendto(句柄, 数据, 长度, 标志, 对端地址, 地址长度)
char *data = "热死了~~";
ret = sendto(sockfd, data, strlen(data), 0, (struct sockaddr*)&paddr, len);
if(ret < 0){
perror("sendto error");
return -1;
}
5.关闭套接字
//5.关闭套接字
close(sockfd);
客户端
- 封装实现一个udpsocket类
- 通过实例化的对象调用对应的成员接口可以实现udp客户端或服务端的搭建
class UdpSocket{
private:
int _sockfd;
public:
UdpSocket()
:_sockfd(-1){}
bool Socket(){
_sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(_sockfd < 0){
perror("socket error");
return false;
}
return true;
}
bool Bind(string &ip, uint16_t port){
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(ip.c_str());
socklen_t len = sizeof(struct sockaddr_in);
int ret;
ret = bind(_sockfd, (struct sockaddr*)&addr, len);
if(ret < 0){
perror("bind error");
return false;
}
return true;
}
bool Send(string &data, string &ip, int port){
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(ip.c_str());
socklen_t len = sizeof(struct sockaddr_in);
int ret = sendto(_sockfd, data.c_str(), data.size(), 0, (struct sockaddr*)&addr, len);
if(ret < 0){
perror("sendto error");
return false;
}
return true;
}
bool Recv(string *buf, string *ip = NULL, int *port = NULL){
struct sockaddr_in addr;
socklen_t len = sizeof(struct sockaddr_in);
char tmp[4096] = {0};
int ret = recvfrom(_sockfd, tmp, 4096, 0, (struct sockaddr*)&addr, &len);
if(ret < 0){
perror("recvfrom error");
return false;
}
buf->assign(tmp, ret);//自带申请空间拷贝数据
if(ip != NULL){
*ip = inet_ntoa(addr.sin_addr);
}
if(port != NULL){
*port = ntohs(addr.sin_port);
}
return true;
}
bool Close(){
if(_sockfd != -1){
close(_sockfd);
}
return true;
}
};
结果演示
此时如果你编译的话就还发现程序报错了!!!
因为我们这里写的是传入字符串, 但我们实际上传入的"192.168.117.135"属于字符串常量, 不匹配
所以我们只需要给前面加上const修饰就好了.
这下就没有问题了
因为我是在同一个主机上同时打开了一个服务端和两个客户端, 所以两个客户端的IP地址都是一样的, 但是你会发现两个客户端的端口是不一样的.
这是因为我们的客户端没有绑定固定的端口, 所以这里的端口是不同的.
此时我们就要思考了, 如果我们在程序里给客户端绑定一个固定的端口会怎么样?
那么, 我们的第二个客户端将运行不起来, 因为第二个客户端要绑定端口的时候, 这个端口已经被第一个客户端给绑定了, 肯定会绑定失败, 程序退出.
所以我们的客户端不推荐绑定地址端口信息, 有要求的情况下才进行绑定