#include<unistd.h>
#include<cstdio>
#include<string>
#include<sys/socket.h>//套接字接口信息
#include<netinet/in.h>//包含地址结构信息
#include<arpa/inet.h>//字节序转换接口
class UdpSocket
{
public:
UdpSocket():_sockfd(-1){}
bool Socket()//创建套接字
{
//socket(地址域,套接字类型,协议类型)
_sockfd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
if(_sockfd<0){
perror("socket error!");
return false;
}
return true;
}
bool Bind(const std::string &ip,uint16_t port)//为套接字绑定地址信息
{
//定义IPV4地址结构 struct sockaddr_in
struct sockaddr_in addr;
addr.sin_family=AF_INET;
addr.sin_port=htons(port);//htons将主机字节序短整型数据转换为网络字节序数据
addr.sin_addr.s_addr=inet_addr(ip.c_str());//将字符串IP地址转换为网络字节序
//bind(描述符,地址信息,地址信息长度)
socklen_t len=sizeof(struct sockaddr_in);
int ret=bind(_sockfd,(struct sockaddr*)&addr,len);
if(ret<0){
perror("bind error!");
return false;
}
return true;
}
bool Recv(std::string* buf,std::string *ip=nullptr,uint16_t *port=nullptr)//接收数据,获取发送端的地址信息
{
//recvfrom(套接字句柄,接收缓存区,数据长度,标识,源端地址,地址长度)
struct sockaddr_in peer_addr;
socklen_t len=sizeof(struct sockaddr_in);
char tmp[4096]={0};
int ret=recvfrom(_sockfd,tmp,4096,0,(struct sockaddr*)&peer_addr,&len);
if(ret<0){
perror("recvfrom error!");
return false;
}
buf->assign(tmp,ret);//assign从指定字符串中截取指定长度的数据放到buf中
if(port!=nullptr){
*port=ntohs(peer_addr.sin_port);//网络字节序到主机字节序的转换
}
if(ip!=nullptr){
*ip=inet_ntoa(peer_addr.sin_addr);//网络字节序到字符串IP地址的转换
}
return true;
}
bool Send(std::string& data,std::string& ip,uint16_t port)//发送数据
{
//sendto(套接字句柄,数据首地址,数据长度,标识,对端地址信息,地址信息长度)
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!\n");
return false;
}
return true;
}
bool Close()//关闭套接字
{
if(_sockfd>0){
close(_sockfd);
_sockfd=-1;
}
return true;
}
private:
int _sockfd;
};
/*********************************************************************/
#include<iostream>
#include<string>
#include"UdpSocket.hpp"
#define CHECK_RET(q) if((q)==false){return false;}
int main(int argc,char* argv[])
{
//argc 标识程序运行参数的个数
// ./udp_srv 192.168.2.2 9000 三个参数
if(argc!=3){
std::cout<<"Usage: ./udp_srv ip port"<<std::endl;
return -1;
}
std::cout<<argv[2]<<std::endl;
uint16_t port=std::stoi(argv[2]);
std::cout<<"Port: "<<port<<std::endl;
std::string ip=argv[1];
std::cout<<"ip: "<<argv[1]<<std::endl;
UdpSocket srv_sock;
//创建套接字
CHECK_RET(srv_sock.Socket());
//绑定地址信息
CHECK_RET(srv_sock.Bind(ip,port));
while(1){
//接收数据
std::string buf;
std::string peer_ip;
uint16_t peer_port;
CHECK_RET(srv_sock.Recv(&buf,&peer_ip,&port));//接收对端数据
std::cout<<"buf: "<<buf<<std::endl;
std::cout<<"peer_ip: "<<peer_ip<<std::endl;
std::cout<<"peer_port: "<<peer_port<<std::endl;
std::cout<< "client["<<peer_ip<<":"<<peer_port<<"] say: "<<buf<<std::endl;
//发送数据
buf.clear();//清空buf
std::cout<<"server say: ";
std::cin>>buf;
CHECK_RET(srv_sock.Send(buf,peer_ip,peer_port));//回复对端数据
}
//关闭套接字
srv_sock.Close();
return 0;
}
/****************************************/
#include<iostream>
#include<string>
#include"UdpSocket.hpp"
#define CHECK_RET(q) if((q)==false) {return -1;}
int main(int argc,char* argv[])
{
//客户端参数获取的IP地址是服务端绑定的地址,也就是客户端发送数据的目标地址
if(argc!=3){
std::cout<<"Usage: ./udp_cli ip port\n";
return -1;
}
std::cout<<argv[1]<<std::endl;
std::cout<<argv[2]<<std::endl;
std::string srv_ip=argv[1];
uint16_t srv_port=std::stoi(argv[2]);
std::cout<<argv[2]<<std::endl;
UdpSocket cli_sock;
//创建套接字
CHECK_RET(cli_sock.Socket());
//绑定地址(不推荐)
while(1){
//发送数据
std::cout<<"client say:";
std::string buf;
std::cin>>buf;
CHECK_RET(cli_sock.Send(buf,srv_ip,srv_port));
//接收数据
buf.clear();
CHECK_RET(cli_sock.Recv(&buf));
std::cout<<"server say: "<<buf<<std::endl;
}
//关闭套接字
cli_sock.Close();
return 0;
}
程序可以运行,客户端可以发送信息给服务端,但是服务端回复信息会报发送信息错误---Invalid argument
client[129.31.37.177:0] say: nihao
服务端收到的客户端信息中客户端的端口始终是0,我怀疑是这里出错了。各位帮忙看看,是怎么回事,怎么解决