在ip数据包头部,有两个ip地址,分别叫做源ip地址和目的ip地址
源ip地址标记着数据是从哪里发出来的,目的ip地址表示发往那台主机
IP地址标定全网内唯一一台主机
端口号标定了特定一台主机上的唯一进程
2. 端口号和pid的关系
我们先对TCP(Transmission Control Protocol 传输控制协议)有一个直观的认识; 后面我们再详细讨论TCP的一些细节问题.
我们只要知道TCP是有连接的面向字节流的可靠传输,TCP要保证数据的可靠性,即不能丢失,因此效率相对来说更低。
此处我们也是对UDP(User Datagram Protocol 用户数据报协议)有一个直观的认识; 后面再详细讨论.
同样我们只要知道UDP是无连接面向数据报的不可靠传输,UDP不管数据可靠性,只负责传输数据,因此更加简单高效
机器有大小端之分,那么如何定义网络数据流的地址呢?
因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址.
为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换
#include
//头文件
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint_32 netlong)
uint16_t ntohs(uint_16 netshort)
速记原则
int socket(int domain, int type, int protocol);
int bind(int socket, const struct sockaddr *address, socklen_t address_len);
socket API是一层抽象的网络编程接口,适用于各种底层网络协议,如IPv4、 IPv6,以及UNIX DomainSocket. 然而, 各种网络协议的地址格式并不相同.
进行通信就需要收发数据,因此还需要两个接口用来收发数据
#include
#include
#include
#include
#include
#include
#include
class udpServer
{
private:
std::string _ip; //ip地址
int _port; //端口号
int _sock; //套接字文件描述符
public:
//构造函数
udpServer(std::string ip = "127.0.0.1", int port = 8080)
:_ip(ip)
,_port(port)
{
}
//初始化服务器
void initServer()
{
//1.创建套接字
_sock = socket(AF_INET, SOCK_DGRAM, 0);
std::cout << "sock:"<< _sock << std::endl;
//2.填重结构体协议,ip,_port
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_addr.s_addr = inet_addr(_ip.c_str());
local.sin_port = htons(_port);
//3.绑定端口,失败直接结束进程
if(bind(_sock,(struct sockaddr*)&local,sizeof(local)) < 0)
{
std::cerr << "bind failed!" << std::endl;
exit(1);
}
}
//启动服务器
void start()
{
//1.创建字符串接收数据
std::cout << "---";
char msg[64] = "\0";
while(1)
{
//定义远端addr结构体用于接收ip地址等
struct sockaddr_in end_point;
socklen_t len = sizeof(end_point);
ssize_t s = recvfrom(_sock, msg, sizeof(msg), 0, (struct sockaddr*)&end_point, &len);
if(s > 0)
{
std::cout << "client#"<< msg << std::endl;
std::string echo_string = msg;
echo_string += "[server echo!]";
sendto(_sock, echo_string.c_str(), echo_string.size(), 0, (struct sockaddr*)&end_point, len);
}
}
}
//析构函数
~udpServer()
{
close(_sock);
}
};
这里我们借助命令行参数,规定使用该程序时需要输入IP地址和端口号
#include "udpServer.hpp"
void Usage(std::string proc)
{
std::cout << "Usage:" << proc << " server_ip server_port"<< std::endl;
}
//./udpServer ip port
int main(int argc, char* argv[])
{
if(argc != 3)
{
Usage(argv[0]);
exit(1);
}
udpServer *up = new udpServer(argv[1],atoi(argv[2]));
up->initServer();
up->start();
delete up;
return 0;
}
#include
#include
#include
#include
#include
#include
class udpClient
{
private:
std::string _ip; //ip地址
int _port; //端口号
int _sock; //套接字文件描述符
public:
//构造函数
udpClient(std::string ip = "127.0.0.1", int port = 8080)
:_ip(ip)
,_port(port)
{
}
//初始化
void initClient()
{
//1.创建套接字
_sock = socket(AF_INET, SOCK_DGRAM, 0);
std::cout << "sock:"<< _sock << std::endl;
// //2.填重结构体协议,ip,_port
// struct sockaddr_in peer;
// peer.sin_family = AF_INET;
// peer.sin_addr.s_addr = inet_addr(_ip.c_str());
// peer.sin_port = htons(_port);
// //3.绑定端口,失败直接结束进程
// if(bind(_sock,(struct sockaddr*)&peer,sizeof(local)) < 0)
// std::cerr << "bind failed!" << std::endl;
// exit(1);
}
//启动
void start()
{
std::string msg;
struct sockaddr_in peer;
peer.sin_family = AF_INET;
peer.sin_addr.s_addr = inet_addr(_ip.c_str());
peer.sin_port = htons(_port);
while(1)
{
std::cout << "Please enter your msg:#";
std::cin >> msg;
if(msg == "quit")
break;
sendto(_sock, msg.c_str(), msg.size(), 0, (struct sockaddr*)&peer, sizeof(peer));
char echo[128];
ssize_t s = recvfrom(_sock, echo, sizeof(echo)-1, 0, nullptr, nullptr);
if(s >0){
echo[s] = 0;
std::cout << "server# " << echo << std::endl;
}
}
}
//析构函数
~udpClient()
{
close(_sock);
}
};
#include "udpClient.hpp"
void Usage(std::string proc)
{
std::cout << proc << "Server_IP" << " server_port" << std::endl;
}
int main(int argc, char * argv[])
{
if(argc != 3)
{
Usage(argv[0]);
exit(1);
}
udpClient *uc = new udpClient(argv[1],atoi(argv[2]));
uc->initClient();
uc->start();
delete uc;
return 0;
}
.PHONY:all
all:udpClient udpServer
udpClient:udpClient.cc
g++ -o $@ $^ -std=c++11
udpServer:udpServer.cc
g++ -o $@ $^
.PHNOY:clean
clean:
rm -f udpClient udpServer