1.示例描述
按照第一篇文章的框架,使用相应的函数来编写一个基于UDP的socket示例,实现同一台主机不同进程之间的通信(不同主机,修改IP地址即可),基于UDP的socket程序最为核心关键的就是sendto和recvfrom函数。具体表现为:开启两个shell终端运行该程序,A终端可以发送消息给B终端;B终端能够接收到消息并打印出来,同时也可以发送消息给A终端,A终端能显示B终端的响应。
下面分别从“客户端”(先发送消息的)和“服务器端”(先回复,再发送消息的)来实现socket程序。
2.“客户端”
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <iostream>
#include <cstring>
//宏定义对方IP地址
#define IP "192.168.120.100"
int main(){
//我方的套接字
int sockfd = socket(PF_INET, SOCK_DGRAM, 0);
if (sockfd == -1)
{
std::cout << "create socket error..." << std::endl;
return -1;
}
//注册我方的地址信息
//如果主机有多张网卡,需要手动分配地址,注册地址信息,表明用来网络传输的是哪张网卡
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("192.168.120.100");
addr.sin_port = htons(8080);
//将我方的地址信息(192.168.120.100:8080)绑定到套接字
if (bind(sockfd, (sockaddr*)&addr, sizeof(addr)) == -1)
{
std::cout << "bind socket error..." << std::endl;
return -1;
}
//输入用户名字
std::cout << "输入你的名字: ";
std::string name;
getline(std::cin, name);
//数据交互
while (true)
{
//我方要发送的消息
std::cout << name << ": ";
std::string msg;
//不能换行再发送消息,否则换行之后的消息在下一次调用sendto函数的时候发送
getline(std::cin, msg);
if (msg == "拜拜") break;
//注册对方的地址信息(192.168.120.100:8081)
sockaddr_in new_addr;
new_addr.sin_family = AF_INET;
new_addr.sin_addr.s_addr = inet_addr(IP);
new_addr.sin_port = htons(8081);
socklen_t len = sizeof(new_addr);
//使用sendto函数发送数据,需要知道对方的地址信息
//使用我方的套接字,将缓冲区的数据发送到通道里(通道另一端的地址需要是已知的)
int send_size = sendto(sockfd, msg.c_str(), msg.size(), 0, (sockaddr*)&new_addr, len);
if (send_size == -1)
{
std::cout << "send to error..." << std::endl;
return -1;
}
//接收数据,测试:空白的地址也可以接收数据
sockaddr_in ano_addr;
socklen_t ano_len = sizeof(ano_addr);
char buff[BUFSIZ];//开辟缓冲区
//使用recvfrom函数接收数据,不需要知道对方的地址信息
int recv_size = recvfrom(sockfd, buff, BUFSIZ, 0, (sockaddr*)&ano_addr, &ano_len);
if (recv_size == -1)
{
std::cout << "recv from error..." << std::endl;
return -1;
}
msg[recv_size] = 0;
std::cout << "对方: " << msg << std::endl;
}
//关闭套接字
close(sockfd);
return 0;
}
3.“服务器端”
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <iostream>
#include <cstring>
//宏定义对方IP地址
#define IP "192.168.120.100"
int main(){
//我方的套接字
int sockfd = socket(PF_INET, SOCK_DGRAM, 0);
if (sockfd == -1)
{
std::cout << "create socket error..." << std::endl;
return -1;
}
//注册我方的地址信息
//如果主机有多张网卡,需要手动分配地址,注册地址信息,表明用来网络传输的是哪张网卡
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("192.168.120.100");
addr.sin_port = htons(8080);
//将我方的地址信息(192.168.120.100:8080)绑定到套接字
if (bind(sockfd, (sockaddr*)&addr, sizeof(addr)) == -1)
{
std::cout << "bind socket error..." << std::endl;
return -1;
}
//输入用户名字
std::cout << "输入你的名字: ";
std::string name;
getline(std::cin, name);
//数据交互
while (true)
{
//我方要发送的消息
std::cout << name << ": ";
std::string msg;
//不能换行再发送消息,否则换行之后的消息在下一次调用sendto函数的时候发送
getline(std::cin, msg);
if (msg == "拜拜") break;
//注册对方的地址信息(192.168.120.100:8081)
sockaddr_in new_addr;
new_addr.sin_family = AF_INET;
new_addr.sin_addr.s_addr = inet_addr(IP);
new_addr.sin_port = htons(8081);
socklen_t len = sizeof(new_addr);
//使用sendto函数发送数据,需要知道对方的地址信息
//使用我方的套接字,将缓冲区的数据发送到通道里(通道另一端的地址需要是已知的)
int send_size = sendto(sockfd, msg.c_str(), msg.size(), 0, (sockaddr*)&new_addr, len);
if (send_size == -1)
{
std::cout << "send to error..." << std::endl;
return -1;
}
//接收数据,测试:空白的地址也可以接收数据
sockaddr_in ano_addr;
socklen_t ano_len = sizeof(ano_addr);
char buff[BUFSIZ];//开辟缓冲区
//使用recvfrom函数接收数据,不需要知道对方的地址信息
int recv_size = recvfrom(sockfd, buff, BUFSIZ, 0, (sockaddr*)&ano_addr, &ano_len);
if (recv_size == -1)
{
std::cout << "recv from error..." << std::endl;
return -1;
}
buff[recv_size] = 0;
std::cout << "对方: " << buff << std::endl;
}
//关闭套接字
close(sockfd);
return 0;
}