目录
一、服务端
1.编写流程
1.1 创建套接字
在内核中创建socket结构体,将进程与网卡关联起来。
1.2 为套接字绑定地址信息
给创建的套接字socket结构体描述源端地址信息。
作用:
1)告诉系统,网卡收到的那条数据应该交给我来处理;
2)当发生数据时,使用绑定的地址信息作为源端地址信息。
1.3 接收数据
从socket的接收缓冲区中取出数据。
1.4 发送数据
把要发送的数据放到发送缓冲区中。
1.5 关闭套接字
2. 代码实现
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<netinet/in.h> //struct_sockaddr_in 结构
#include<arpa/inet.h> //字节序转换接口
#include<sys/socket.h> //socket接口头文件
#include<string.h>
int main() {
//1.创建套接字
int sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sockfd < 0) {
perror("Create socket error!");
return -1;
}
//2.为套接字绑定地址信息
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(8888);
addr.sin_addr.s_addr = inet_addr("192.168.247.128");
socklen_t len = sizeof(struct sockaddr_in);
int ret = bind(sockfd, (struct sockaddr*)&addr, len);//绑定地址信息
if (ret < 0) {
perror("bind error!");
return -1;
}
//接收&发送 数据
while (1) {
//3.接收数据
char buf[1024] = {0};
struct sockaddr_in client;//保存发送方的地址信息
ret = recvfrom(sockfd, buf, 1023, 0, (struct sockaddr*)&client, &len);
if (ret < 0) {
perror("recvfrom error!");
close(sockfd);
return -1;
}
//打印客户端的信息
printf("client:%s 端口:%d 数据:%s\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port), buf);
//4.发送数据
printf("server send: ");
fflush(stdout);
char data[1024] = {0};
fgets(data, 1023, stdin);
ret = sendto(sockfd, data, strlen(data), 0, (struct sockaddr*)&client, len);
if (ret < 0) {
perror("sendto error!");
close(sockfd);
return -1;
}
}
//5.关闭套接字
close(sockfd);
return 0;
}
二、客户端
1.编写流程
1.1 创建套接字
1.2 为套接字绑定地址信息(不推荐)
客户端并不推荐主动绑定地址。
原因:
1)绑定之后,程序只能启动一个;
2)客户端并不需要固定使用某个地址。
1.3 向服务器发送数据
发送数据前,若socket没有绑定指定地址,则系统会自动选择一个合适的地址信息进行绑定。
1.4 接收数据
1.5 关闭套接字
2. 代码实现
通过封装一个客户端类,可以更加便捷的创建多个客户端。
2.1 客户端头文件-类封装
#include<iostream>
#include<string>
#include<unistd.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/socket.h>
//封装UDPsocket类
//通过类实例化对象,调用成员接口,简单的完成服务器与客户端搭建
class UDPsocket {
private:
int _sockfd;
public:
UDPsocket() : _sockfd(-1) {}
~UDPsocket() {if(_sockfd != -1) close(_sockfd);}
//1.创建套接字
bool Socket() {
_sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (_sockfd < 0) {
perror("create socket error!");
return false;
}
return true;
}
//2.绑定地址信息
bool Bind(const std::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 = bind(_sockfd, (struct sockaddr*)&addr, len);
if (ret < 0) {
perror("bind error!");
return false;
}
return true;
}
//3.发送数据
bool Send(const std::string &data, const std::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 = sendto(_sockfd, data.c_str(), data.size(), 0, (struct sockaddr*)&addr, len);
if (ret < 0) {
perror("sendto error!");
return false;
}
return true;
}
//4.接收数据
bool Recve(std::string *buf, std::string *ip = NULL, uint16_t *port = NULL) {
struct sockaddr_in addr;
socklen_t len = sizeof(struct sockaddr_in);
char temp[4096] = {0};
int ret = recvfrom(_sockfd, temp, 4095, 0, (struct sockaddr*)&addr, &len);
if (ret < 0) {
perror("recvfrom error!");
return false;
}
if (ip != NULL) *ip = inet_ntoa(addr.sin_addr);
if (port != NULL) *port = ntohs(addr.sin_port);
*buf = temp;
return true;
}
//5.关闭套接字
bool Close() {
if (_sockfd != -1) close(_sockfd);
return true;
}
};
2.2 客户端实现
#include "udp_socket.hpp"
#define CHECK_RETURN(x) if ((x) == false) {return -1;}
int main(int argc, char *argv[]) {
if (argc != 3) {
std::cout<<"Usage: ./udp_client ip port"<< std::endl;
std::cout<<"Server address!"<< std::endl;
return -1;
}
UDPsocket sock;//创建客户端对象
std::string srv_ip = argv[1];
int srv_port = std::stoi(argv[2]);
//1.创建套接字
CHECK_RETURN(sock.Socket());
//2. 绑定地址信息----客户端不推荐
while (1) {
std::cout<<"client send:";
fflush(stdout);
std::string buf;
std::cin>>buf;
//3.发送数据
CHECK_RETURN(sock.Send(buf, srv_ip, srv_port));
//4.接收数据
buf.clear();
CHECK_RETURN(sock.Recve(&buf));
std::cout<<"server reply:" << buf << std::endl;
}
//5.关闭套接字
CHECK_RETURN(sock.Close());
return 0;;
}