一、结构体
结构体 |
功能 |
特性 |
struct sockaddr |
套接字地址结构 |
IPv4 / IPv6 |
struct sockaddr_in |
IPv4套接字地址结构 |
IPv4 |
struct in_addr |
IPv4地址结构 |
IPv4 |
struct sockaddr_in6 |
IPv6套接字地址结构 |
IPv6 |
// 套接字地址结构
struct sockaddr
{
unsigned short sa_family; // 套接字地址簇类型,为 AF_INET
char sa_data[14]; // 套接字地址数据(14位协议地址)
};
// IPv4 套接字地址结构
struct sockaddr_in
{
short sin_family; // 套接字地址簇类型,为 AF_INET
unsigned short sin_port; // 端口号,网络字节序
struct in_addr sin_addr; // IP地址,网络字节序
unsigned char sin_zero[8]; // 填充字节,用来保证struct sockaddr_in的大小和struct sockaddr的大小相等
};
// IPv4 地址类型
typedef unsigned int in_addr_t;
// IPv4 地址结构
struct in_addr
{
in_addr_t s_addr;
};
// IPv6 套接字地址结构
struct sockaddr_in6
{
uint8_t sin6_len; // 固定为24字节长度
sa_family_t sin6_family; // 套接字地址簇类型,为 AF_INET6
in_port_t sin6_port; // 16位端口号,网络字节序
uint32_t sin6_flowinfo; // 32位流标签
struct in6_addr sin6_addr; // 128位IP地址
};
二、转换接口
头文件:arpa/inet.h
1、字节序转换
函数 |
作用 |
ntohs() |
将unsigned short 类型从网络序转换到主机序 |
ntohl() |
将unsigned long 类型从网络序转换到主机序 |
函数 |
作用 |
htons() |
将unsigned short 类型从主机序转换到网络序 |
htonl() |
将unsigned long 类型从主机序转换到网络序 |
实例:
#include <iostream>
#include <cstring>
#include <iomanip>
#include <arpa/inet.h>
void Hex(int n)
{
char bytes[2];
memcpy(bytes, &n, 2);
std::cout << showbase << setw(2) << setfill('0')
<< hex << (int)bytes[0] << setw(2) << (int)bytes[1] << std::endl;
}
int main()
{
uint16_t n = 16;
Hex(n);
uint16_t m = htons(n);
Hex(m);
uint16_t t = ntohs(m);
Hex(t);
return 0;
}
2、IP地址转换
函数 |
功能 |
特点 |
int inet_aton(const char *string, struct in_addr *addr) |
点分十进制数串转长整型网络字节序 |
IPv4 |
in_addr_t inet_addr(const char *string) |
点分十进制数串转长整型网络字节序 |
IPv4 |
char* inet_ntoa(struct in_addr addr) |
长整型网络字节序转点分十进制数串 |
IPv4 |
int inet_pton(int af, const char *src, void *dst) |
点分十进制数串转长整型网络字节序 |
IPv4 / IPv6 |
const char* inet_ntop(int af, const void *src, char *dst, socklen_t cnt) |
长整型网络字节序转点分十进制数串 |
IPv4 / IPv6 |
实例:
#include <iostream>
#include <cstring>
#include <arpa/inet.h>
int main()
{
std::string s = "192.168.0.1";
struct in_addr addr;
inet_aton(s.c_str(), &addr);
std::cout << hex << addr.s_addr << "\n"
<< inet_ntoa(addr) << "\n"
<< inet_addr(s.c_str()) << std::endl;
return 0;
}
3、主机名转换
函数 |
功能 |
struct hostent* gethostbyname(const char *hostname) |
主机名转地址 |
struct hostent* gethostbyaddr(const char *addr, int len, int type) |
地址转主机名 |
参数 |
含义 |
h_name |
主机名 |
h_aliases |
以空指针结尾的主机别名队列 |
h_addrtype |
地址类型,AF_INET / AF_INET6 |
h_length |
地址长度,在AF_INET 类型地址中为4 |
h_addr |
第一个IP地址 |
h_addr_list |
以空指针结尾的IP地址的列表 |
三、Socket操作
头文件:sys/socket.h
1、创建
/**
* 参数
* domain: 协议域 - AF_INET (IPv4); AF_INET6 (IPv6); AF_LOCAL (Unix)
* type: 类型 - 流套接字 (SOCK_STREAM); 数据报套接字 (SOCK_DGRAM); 原始套接字 (SOCK_RAW)
* protocol: 协议 - 0 (自动根据 type 匹配协议); IPPROTO_TCP / IPPROTO_UDP
*
* 返回值
* -1 表示失败, 否则返回 socket 描述符 (>0)
*/
int socket(int domain, int type, int protocol);
2、关闭
/**
* 参数
* sockfd: socket 描述符
* howto: 关闭方式 - SHUT_RD (值为0, 关闭连接的读); SHUT_WR (值为1, 关闭连接的写); SHUT_RDWR (值为2, 连接读写都关闭)
*
* 返回值
* 成功返回 0, 失败返回 -1
*/
int close(int sockfd);
int shutdown(int sockfd, int howto);
// 区别
// 1、close 把描述符的引用计数减 1,仅在该计数变为 0 时关闭套接字。shutdown 可以不管引用计数就激发 TCP 的正常连接终止序列
// 2、close 终止读和写两个方向的数据发送。TCP 为全双工,有时候需要告知对方已经完成了数据传送,即使对方仍有数据要发送
3、属性
/**
* 参数
* sockfd: socket 描述符
* level: 选项层次 - SOL_SOCKET (通用套接字选项); IPPROTO_TCP (TCP选项); IPPROTO_IP (IP选项); IPPROTO_IPV6 (IPv6选项)
* optname: 选项
* optval: 选项值指针
* optlen: optval缓冲区长度
*
* 返回值
* 成功返回 0, 失败返回 -1
*/
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
4、获取
int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);
5、绑定
/**
* 参数
* socket: 套接字描述符
* address: 地址和端口号
* address_len: address 缓冲区长度
*
* 返回值
* 成功返回 0, 失败返回 SOCKET_ERROR
*/
int bind(int socket, const struct sockaddr *address, socklen_t address_len);
6、监听
/**
* 参数
* sockfd: 监听的 socket 描述符
* backlog: 排队的最大连接个数
*
* 返回值
* 成功返回 0, 失败返回 -1
*/
int listen(int sockfd, int backlog);
7、连接
/**
* 参数
* sockfd: 客户端 socket 描述符
* addr: 服务器的 socket 地址
* addrlen: 服务器的 socket 地址长度
*
* 返回值
* 成功返回 0, 失败返回 -1
*/
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
8、接收连接
/**
* 参数
* sockfd: 服务器 socket 描述符, 监听 socket 描述符
* addr: 客户端 socket 地址
* addrlen: 客户端 socket 地址长度
*
* 返回值
* 失败返回 -1, 否则返回连接描述符
*/
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
说明
如果不需要获取客户端套接字地址,addr
和addrlen
传入NULL
;
如果需要获取,参考如下例子:
struct sockaddr_in remote_addr;
bzero(&remote_addr, sizeof(remote_addr));
socklen_t remote_addr_len = sizeof(remote_addr);
int connfd = accept(listenfd, (struct sockaddr*)&remote_addr, &remote_addr_len);
9、发送数据
/**
* 参数
* fd: 文件描述符
* buf: 写入数据
* len: 写入数据的长度
*
* 返回值
* 出错 <0, 否则返回实际所写字节数
*/
ssize_t write(int fd, const void *buf, size_t len);
ssize_t send(int sockfd, const void *buf, size_t len, int flags); // flags 通常为 0
/**
* 参数
* sockfd: socket 描述符
* buf: 写入数据
* len: 写入数据长度
* flags: 通常为 0
* dst_addr: 目标 socket 地址
* addrlen: 目标 socket 地址长度
*
* 返回值
* 出错 <0, 否则返回实际所写字节数
*/
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dst_addr, socklen_t addrlen);
10、接收数据
// 返回值:
// 0 - 读到文件结束
// >0 - 实际所写字节数
// <0 - 出错
ssize_t read(int fd, void *buf, size_t len);
ssize_t recv(int sockfd, void *buf, size_t len, int flags); // flags 通常为 0
/**
* 参数
* sockfd: socket 描述符
* buf: 读取数据
* len: 读取长度
* flags: 通常为 0
* src_addr: 源端 socket 地址
* addrlen: 源端 socket 地址长度
*/
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
四、TCP
1、客户端伪码
main()
{
// 1、打开套接字
fd = socket();
// 2、连接服务器
connect(fd);
// 3、写入/读取数据
write(fd);
read(fd);
// 4、关闭套接字
close(fd);
}
2、服务端伪码
main()
{
// 1、打开套接字
fd = socket();
// 2、绑定
bind(fd);
// 3、监听
listen(fd, backlog);
// 4、接收客户端连接
connfd = accept(fd);
// 5、读/写数据
read(connfd);
write(connfd);
// 6、关闭套接字
close(connfd);
close(fd);
}
3、TCP 实例
#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
// Client
int Client()
{
int fd = socket(AF_INET, SOCK_STREAM, 0);
if(-1 == fd)
{
perror("open socket");
return -1;
}
sockaddr_in addr;
addr.sin_family = AF_INET;
inet_aton("127.0.0.1", &addr.sin_addr);
addr.sin_port = htons(8080);
if(-1 == connect(fd, (struct sockaddr*)&addr, sizeof(addr)))
{
perror("connect");
return -1;
}
std::string s;
std::cin >> s;
write(fd, s.c_str(), s.size() + 1);
char buf[256] = {0};
read(fd, buf, 256);
std::cout << buf << std::endl;
close(fd);
return 0;
}
// Server
int Server()
{
int fd = socket(AF_INET, SOCK_STREAM, 0);
if(-1 == fd)
{
perror("open socket");
return -1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
inet_aton("127.0.0.1", &addr.sin_addr);
addr.sin_port = htons(8080);
if(-1 == bind(fd, (struct sockaddr*)&addr, sizeof(addr)))
{
perror("bind");
return -1;
}
if(-1 == listen(fd, 4))
{
perror("listen");
return -1;
}
int connfd = accept(fd, NULL, NULL);
if(-1 == connfd)
{
perror("accept");
return -1;
}
char buf[256] = {0};
read(connfd, buf, 256);
std::cout << buf << std::endl;
std::string s;
std::cin >> s;
write(connfd, s.c_str(), s.size() + 1);
close(connfd);
close(fd);
return 0;
}
4、父子进程实例
#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
using namespace std;
// Client
int main(int argc, char *argv[])
{
if (3 != argc)
{
cout << "argument error" << "\n";
cout << "Usage:" << argv[0] << "sever_ip sever_port" << endl;
return 1;
}
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == fd)
{
perror("open socket");
return 1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
inet_aton(argv[1], &addr.sin_addr);
addr.sin_port = htons(atoi(argv[2]));
int res = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
if (-1 == res)
{
perror("connect");
return 1;
}
if (fork())
{
string s;
while (cin >> s)
{
write(fd, s.c_str(), s.size() + 1);
}
}
else
{
for (;;)
{
char buffer[256] = {0};
read(fd, buffer, 256);
cout << buffer << endl;
}
}
close(fd);
return 0;
}
// Server
int main(int argc, char *argv[])
{
if (3 != argc)
{
cout << "argument error" << "\n";
cout << "Usage:" << argv[0] << "sever_ip sever_port" << endl;
return 1;
}
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == fd)
{
perror("open socket");
return 1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
inet_aton(argv[1], &addr.sin_addr);
addr.sin_port = htons(atoi(argv[2]));
int res = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
if (-1 == res)
{
perror("bind");
return 1;
}
res = listen(fd, 4);
if (-1 == res)
{
perror("listen");
return 1;
}
int connfd = accept(fd, NULL, NULL);
if (-1 == connfd)
{
perror("accept");
return 1;
}
if (fork())
{
for (;;)
{
char buffer[256] = {0};
read(connfd, buffer, 256);
cout << buffer << endl;
}
}
else
{
string s;
while (cin >> s)
{
write(connfd, s.c_str(), s.size() + 1);
}
}
close(connfd);
close(fd);
return 0;
}
5、C++ 多线程实例
#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <thread>
using namespace std;
// Client
int main(int argc, char *argv[])
{
if (3 != argc)
{
cout << "argument error" << "\n";
cout << "Usage:" << argv[0] << "sever_ip sever_port" << endl;
return 1;
}
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == fd)
{
perror("open socket");
return 1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
inet_aton(argv[1], &addr.sin_addr);
addr.sin_port = htons(atoi(argv[2]));
int res = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
if (-1 == res)
{
perror("connect");
return 1;
}
thread t([fd](){
for(;;)
{
char buffer[256] = {0};
int n = read(fd,buffer,256);
if(0 == n)
{
cout << "sever exit!" << endl;
break;
}
cout << buffer << endl;
}
});
t.detach();
string s;
while (cin >> s)
{
write(fd, s.c_str(), s.size() + 1);
}
close(fd);
return 0;
}
// Server
int main(int argc, char *argv[])
{
if (3 != argc)
{
cout << "argument error" << "\n";
cout << "Usage:" << argv[0] << "sever_ip sever_port" << endl;
return 1;
}
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == fd)
{
perror("open socket");
return 1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
inet_aton(argv[1], &addr.sin_addr);
addr.sin_port = htons(atoi(argv[2]));
int res = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
if (-1 == res)
{
perror("bind");
return 1;
}
res = listen(fd, 4);
if (-1 == res)
{
perror("listen");
return 1;
}
int connfd = accept(fd, NULL, NULL);
if (-1 == connfd)
{
perror("accept");
return 1;
}
thread t([connfd](){
for(;;)
{
char buffer[256] = {0};
int n = read(connfd,buffer,256);
if(0 == n)
{
cout << "client exit!" << endl;
break;
}
cout << buffer << endl;
}
});
t.detach();
string s;
while (cin >> s)
{
write(connfd, s.c_str(), s.size() + 1);
}
close(connfd);
close(fd);
return 0;
}
6、多客户端实例
#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <thread>
#include <vector>
using namespace std;
// Server
int main(int argc, char *argv[])
{
if (3 != argc)
{
cout << "argument error" << "\n";
cout << "Usage:" << argv[0] << "sever_ip sever_port" << endl;
return 1;
}
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == fd)
{
perror("open socket");
return 1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
inet_aton(argv[1], &addr.sin_addr);
addr.sin_port = htons(atoi(argv[2]));
int res = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
if (-1 == res)
{
perror("bind");
return 1;
}
cout << "bind" << endl;
res = listen(fd, 4);
if (-1 == res)
{
perror("listen");
return 1;
}
cout << "listen" << endl;
// 向多个客户端发送
vector<int> fds;
thread writer(
[&]()
{
string s;
while(cin >> s)
{
for(auto connfd : fds)
{
write(connfd, s.c_str(), s.size() + 1);
}
}
}
);
writer.detach();
for (;;)
{
struct sockaddr_in remote_addr;
socklen_t len = sizeof(remote_addr);
int connfd = accept(fd, (sockaddr *)&remote_addr, &len);
// 打印哪个客户端连接服务器
cout << inet_ntoa(remote_addr.sin_addr) << ":" << ntohs(remote_addr.sin_port) << endl;
if (-1 == connfd)
{
perror("accept");
return 1;
}
fds.push_back(connfd);
cout << "accept" << endl;
thread t(
[connfd]()
{
for (;;)
{
char buffer[256] = {0};
int n = read(connfd, buffer, 256);
if (0 == n)
{
cout << "client exit!" << endl;
break;
}
cout << buffer << endl;
}
}
);
t.detach();
}
for (auto connfd : fds)
{
close(connfd);
}
close(fd);
return 0;
}
7、文件服务器实例
#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/sendfile.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <thread>
#include <vector>
using namespace std;
// Client
int main(int argc, char *argv[])
{
if (3 != argc)
{
cout << "argument error" << "\n";
cout << "Usage:" << argv[0] << "sever_ip sever_port" << endl;
return 1;
}
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == fd)
{
perror("open socket");
return 1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
inet_aton(argv[1], &addr.sin_addr);
addr.sin_port = htons(atoi(argv[2]));
int res = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
if (-1 == res)
{
perror("connect");
return 1;
}
string s;
cin >> s;
write(fd, s.c_str(), s.size() + 1);
int pos = s.find_last_of('/');
//查询是否找到
if (pos != string::npos)
{
s = s.substr(pos);
}
string file = "./" + s;
cout << file << endl;
int filefd = open(file.c_str(), O_CREAT | O_WRONLY, 0666);
if (-1 == filefd)
{
perror("open file");
return 1;
}
//下载文件
for (;;)
{
char buffer[256] = {0};
int n = read(fd, buffer, 256);
write(filefd, buffer, n);
if (n < 256)
{
break;
}
}
close(filefd);
close(fd);
return 0;
}
// Server
int main(int argc, char *argv[])
{
if (4 != argc)
{
cout << "argument error" << "\n";
cout << "Usage:" << argv[0] << "sever_ip sever_port path" << endl;
return 1;
}
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == fd)
{
perror("open socket");
return 1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
inet_aton(argv[1], &addr.sin_addr);
addr.sin_port = htons(atoi(argv[2]));
int res = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
if (-1 == res)
{
perror("bind");
return 1;
}
res = listen(fd, 4);
if (-1 == res)
{
perror("listen");
return 1;
}
int connfd = accept(fd, NULL, NULL);
if (-1 == connfd)
{
perror("accept");
return 1;
}
char buffer[256] = {0};
read(connfd, buffer, 256);
cout << buffer << endl;
string file = string(argv[3]) + "/" + buffer;
cout << "require " << file.c_str() << endl;
int filefd = open(file.c_str(), O_RDONLY);
if (-1 == filefd)
{
perror("open file");
return 1;
}
struct stat s;
fstat(filefd, &s);
sendfile(connfd, filefd, 0, s.st_size);
close(connfd);
close(fd);
return 0;
}
8、多客户端文件服务
#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/sendfile.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <thread>
#include <vector>
using namespace std;
// Client
int main(int argc, char *argv[])
{
if (3 != argc)
{
cout << "argument error" << "\n";
cout << "Usage:" << argv[0] << "sever_ip sever_port" << endl;
return 1;
}
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == fd)
{
perror("open socket");
return 1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
inet_aton(argv[1], &addr.sin_addr);
addr.sin_port = htons(atoi(argv[2]));
int res = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
if (-1 == res)
{
perror("connect");
return 1;
}
for (;;)
{
char buffer[1024] = {0};
int n = read(fd, buffer, 1024);
write(STDOUT_FILENO, buffer, n);
if (n < 1024)
{
break;
}
}
string s;
while (cin >> s)
{
write(fd, s.c_str(), s.size() + 1);
int pos = s.find_last_of('/');
//查询是否找到
if (pos != string::npos)
{
s = s.substr(pos);
}
string file = "./" + s;
cout << file << endl;
int filefd = open(file.c_str(), O_CREAT | O_WRONLY, 0666);
if (-1 == filefd)
{
perror("open file");
return 1;
}
//下载文件
for (;;)
{
char buffer[256] = {0};
int n = read(fd, buffer, 256);
write(filefd, buffer, n);
if (n < 256)
{
break;
}
}
close(filefd);
}
close(fd);
return 0;
}
// Server
int main(int argc, char *argv[])
{
if (4 != argc)
{
cout << "argument error" << "\n";
cout << "Usage:" << argv[0] << "sever_ip sever_port path" << endl;
return 1;
}
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == fd)
{
perror("open socket");
return 1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
inet_aton(argv[1], &addr.sin_addr);
addr.sin_port = htons(atoi(argv[2]));
int res = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
if (-1 == res)
{
perror("bind");
return 1;
}
res = listen(fd, 4);
if (-1 == res)
{
perror("listen");
return 1;
}
for (;;)
{
int connfd = accept(fd, NULL, NULL);
if (-1 == connfd)
{
perror("accept");
return 1;
}
string cmd = string("ls -lR ") + argv[3];
FILE *pfile = popen(cmd.c_str(), "r");
if (NULL == pfile)
{
perror("popen");
return 1;
}
for (;;)
{
char info[1025] = {0};
int n = fread(info, 1, 1024, pfile);
write(connfd, info, n);
if (n < 1024)
{
break;
}
}
pclose(pfile);
thread t(
[=]()
{
for(;;)
{
char buffer[256] = {0};
int n = read(connfd,buffer,256);
if(n <= 0)
{
break;
}
cout << buffer << endl;
//请求文件的路径
string file = string(argv[3]) + "/" + buffer;
cout << "require " << file.c_str() << endl;
int filefd = open(file.c_str(), O_RDONLY);
if(-1 == filefd)
{
perror("open file");
return;
}
struct stat s;
fstat(filefd, &s);
sendfile(connfd, filefd, 0, s.st_size);
}
close(connfd);
}
);
t.detach();
}
close(fd);
return 0;
}
五、UDP
1、单播
// Client
main()
{
// 打开 socket
connfd = socket(AF_INET, SOCK_DGRAM, 0);
// 设置IP和端口
struct sockaddr_in si;
si.sin_family = AF_INET;
si.sin_port = htons(port);
si.sin_addr.s_addr = inet_addr(ip);
// 发送数据
sendto(connfd, buf, buf_size, 0, (struct sockadrr *)&si, sizeof(si));
// 关闭 socket
close(connfd);
}
// Server
main()
{
// 打开 socket
connfd = socket(AF_INET, SOCK_DGRAM, 0);
// 设置IP和端口
struct sockaddr_in si;
si.sin_family = AF_INET;
si.sin_port = htons(port);
si.sin_addr.s_addr = INADDR_ANY; // 接收任意IP、任意网卡发给指定端口的数据
// 绑定端口
bind(connfd, (struct socket *)&si, sizeof(si));
// 接收数据
recv(connfd, buf, buf_size, 0);
// 关闭 socket
close(connfd);
}
#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
using namespace std;
// Client
int main(int argc, char *argv[])
{
if (3 != argc)
{
cout << "argument error" << "\n";
cout << "Usage:" << argv[0] << "send_ip send_port" << endl;
return 1;
}
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (-1 == fd)
{
perror("open socket");
return 1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
inet_aton(argv[1], &addr.sin_addr);
addr.sin_port = htons(atoi(argv[2]));
string s;
getline(cin, s);
sendto(fd, s.c_str(), s.size() + 1, 0, (struct sockaddr *)&addr, sizeof(addr));
close(fd);
return 0;
}
// Server
int main(int argc, char *argv[])
{
if (3 != argc)
{
cout << "argument error" << "\n";
cout << "Usage:" << argv[0] << "recv_ip recv_port" << endl;
return 1;
}
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (-1 == fd)
{
perror("open socket");
return 1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
inet_aton(argv[1], &addr.sin_addr);
addr.sin_port = htons(atoi(argv[2]));
bind(fd, (struct sockaddr *)&addr, sizeof(addr));
char buffer[1024] = {0};
recv(fd, buffer, 1023, 0);
cout << buffer << endl;
close(fd);
return 0;
}
#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
using namespace std;
// Client
int main(int argc, char *argv[])
{
if (3 != argc)
{
cout << "argument error" << endl;
cout << "Usage:" << argv[0] << "send_ip send_port" << endl;
return 1;
}
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (-1 == fd)
{
perror("open socket");
return 1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
inet_aton(argv[1], &addr.sin_addr);
addr.sin_port = htons(atoi(argv[2]));
string s;
getline(cin, s);
sendto(fd, s.c_str(), s.size() + 1, 0, (struct sockaddr *)&addr, sizeof(addr));
char buffer[1024] = {0};
recv(fd, buffer, 1023, 0);
cout << buffer << endl;
close(fd);
return 0;
}
// Server
int main(int argc, char *argv[])
{
if (3 != argc)
{
cout << "argument error" << endl;
cout << "Usage:" << argv[0] << "recv_ip recv_port" << endl;
return 1;
}
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (-1 == fd)
{
perror("open socket");
return 1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
inet_aton(argv[1], &addr.sin_addr);
addr.sin_port = htons(atoi(argv[2]));
bind(fd, (struct sockaddr *)&addr, sizeof(addr));
char buffer[1024] = {0};
struct sockaddr_in remote_addr;
socklen_t len = sizeof(remote_addr);
recvfrom(fd, buffer, 1023, 0, (struct sockaddr *)&remote_addr, &len);
cout << buffer << endl;
string s;
getline(cin, s);
sendto(fd, s.c_str(), s.size() + 1, 0, (struct sockaddr *)&remote_addr, len);
close(fd);
return 0;
}
2、多播 / 组播
// 客户端流程与单播一致
// Server
main()
{
// 打开套接字
fd = socket(AF_INET, SOCK_DGRAM, 0);
// 构建服务器地址结构
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(port);
// 绑定
bind(fd, server_addr, sizeof(server_addr));
// 构建多播属性结构
struct ip_mreqn group;
inet_pton(AF_INET, GROUP, &group.imr_multiaddr); // 设置多播地址
inet_pton(AF_INET, "0.0.0.0", &group.imr_address); // 设置本地地址
group.imr_ifindex = if_nametoindex("ent0"); // 设置网卡接口
// 设置多播权限和属性
setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &group, sizeof(group));
// 设置客户端多播地址
struct sockaddr_in cliaddr;
bzero(&cliaddr, sizeof(cliaddr));
cliaddr.sin_family = AF_INET;
inet_pton(AF_INET, GROUP, &cliaddr.sin.addr.s_addr);
cliaddr.sin_port = htons(CLIENT_PORT);
// 发送数据
sendto(fd, buf, strlen(buf), 0, (struct sockaddr *)&cliaddr, sizeof(cliaddr));
// 关闭套接字
close(fd);
}
#include <iostream>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
using namespace std;
int main(int argc, char *argv[])
{
if (4 != argc)
{
cout << "argument error" << endl;
cout << "Usage:" << argv[0] << "recv_ip recv_port multi_ip" << endl;
return 1;
}
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (-1 == fd)
{
perror("open socket");
return 1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
inet_aton(argv[1], &addr.sin_addr);
addr.sin_port = htons(atoi(argv[2]));
bind(fd, (struct sockaddr *)&addr, sizeof(addr));
struct ip_mreq group;
group.imr_multiaddr.s_addr = inet_addr(argv[3]);
group.imr_interface.s_addr = inet_addr(argv[1]);
if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&group, sizeof(group)) < 0)
{
perror("Adding multicast group");
close(fd);
return 1;
}
char buffer[1024] = {0};
recv(fd, buffer, 1023, 0);
cout << buffer << endl;
close(fd);
return 0;
}
3、广播
// 服务端流程与单播一致
// Client
main()
{
// 打开 socket
cfd = socket(AF_INET, SOCK_DGRAM, 0);
// 打开广播
setsockopt(cfd, SOL_SOCKET, SO_BROADCAST, &n, sizeof(n)); // 参数 n - 0 表示关闭, 非 0 表示打开
// 设置IP和端口
struct sockaddr_in si;
si.sin_family = AF_INET;
si.sin_port = htons(port);
si.sin_addr.s_addr = inet_addr("255.255.255.255");
// 发送数据
sendto(cfd, buf, buf_size, 0, (struct sockaddr *)&si, sizeof(si));
// 关闭 socket
close(socket);
}
#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
using namespace std;
int main(int argc, char *argv[])
{
if (3 != argc)
{
cout << "argument error" << endl;
cout << "Usage:" << argv[0] << "send_ip send_port" << endl;
return 1;
}
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (-1 == fd)
{
perror("open socket");
return 1;
}
int opt = 1;
if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char *)&opt, sizeof(opt)) == -1)
{
perror("setsockopt");
close(fd);
return 1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
inet_aton(argv[1], &addr.sin_addr);
addr.sin_port = htons(atoi(argv[2]));
string s;
getline(cin, s);
sendto(fd, s.c_str(), s.size() + 1, 0, (struct sockaddr *)&addr, sizeof(addr));
close(fd);
return 0;
}