目录
echo服务器:将收到的消息回显到客户端。
主要目的:学习网络系统调用接口的使用,和一些网络基础知识
1.接口
1.1 socket
#include <sys/types.h>
#include <sys/socket.h>int socket(int domain, int type, int protocol);
//创建套接字 成功返回文件描述符,失败返回-1
domain:选择网络通信的协议族,也叫域,决定了socket在什么网络下通信
type:指定套接字的类型,SOCK_STREAM面相数据流,SOCK_DGRAM面相数据报。
protocol:填好前两个参数,置为零即可
1.2bind
#include <sys/types.h>
#include <sys/socket.h>int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
//将创建好的套接字与网络绑定起来(IP, port)
绑定成功返回 0 失败返回-1
sockfd:socket返回的文件描述符
addr:Socket编程中用于表示地址的通用结构体,它定义了一个通用的地址格式,这里玩了一个多态,sockaddr可以接收sockaddr_in,sockaddr_un传参的时候需要强转为sockaddr,在传参之前,sockaddr_in前三个字段都是要被填充的,其他也一样。
addrlen:参数2的大小
2.实现
2.1server
#pragma once
#include <iostream>
#include <string>
#include "log.hpp"
#include <sys/types.h>
#include <sys/socket.h>
#include <cstring>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
enum
{
SocketError = 1,
BindError = 2,
usageError = 3,
};
class Udpserver
{
public:
Udpserver(uint16_t port)
: _port(port), _isrunning(false), _socketfd(0)
{}
void init()
{
_socketfd = socket(AF_INET, SOCK_DGRAM, 0);
if (_socketfd < 0)
{
Log(FATAL, "Socket Error: ,%s errno:%d", strerror(errno), errno);
exit(SocketError);
}
//创建socket成功
Log(Info,"Socker Success _Socketfd:%d", _socketfd);
//开始绑定
//将创建好套接字,与网络关联起来。
struct sockaddr_in local;
bzero(&local,sizeof(local));//必须置为0否则会段错误
local.sin_family = AF_INET;//绑定协议族
local.sin_port = htons(_port); //网络是大端,需要转换
//in_addr_t tmp = inet_addr("127.0.0.1"); //将字符串转化为uint_32 ip && 转化为大端
// local.sin_addr.s_addr = tmp;
local.sin_addr.s_addr = INADDR_ANY;//绑定任意IP,不建议绑定确定的ip
//一台主机有很多种IP,一旦绑定确定的某个IP,使用其他种的IP就不能访问到服务器
int n = bind(_socketfd, (struct sockaddr*)&local, sizeof(local));
if(n < 0)
{
Log(FATAL, "Bind Errorr: ,%s errno:%d", strerror(errno), errno);
exit(BindError);
}
Log(Info,"Bind Success");
}
void start()
{
_isrunning = true;
while(true)
{
char buffer[1024];
struct sockaddr_in peer;
bzero(&peer,sizeof(buffer));
socklen_t addrlen = sizeof(peer);//既是输入型参数,也是输出型参数,必须初始化
ssize_t n = recvfrom(_socketfd, buffer, sizeof(buffer)-1, 0,(struct sockaddr*)&peer, &addrlen);
if(n > 0) //读取数据成功
{
buffer[n] = 0;
Log(Info, "[get message:%s]\n",buffer);
//将消息重新发送回去
sendto(_socketfd, buffer, sizeof(buffer)-1, 0,(struct sockaddr*)&peer, addrlen);
}
}
_isrunning = false;
}
private:
uint16_t _port; // 端口号
int _socketfd; // socket返回的文件描述符
bool _isrunning; //服务器是否运行
};
注意:
1.绑定ip的时候要使用INADDR_ANY,这样使用这台主机的任意一个ip都可以访问服务器
2.电脑分为小端机和大端机,但是在网络中只有大端,所以端口号和ip都要转化为大端。
3.客户端不用显示的绑定,端口号会自动分配,防止冲突,就会出现打开京东就打不开淘宝的问题。