目录
1. 常用接口
2. C/S 回声模拟
3. C/S myshell 的制作
Linux网络编程✨
1. 常用接口
socket:创建套接字:
// 创建 socket 文件描述符
int socket(int domain, int type, int protocol);
返回值:
- 套接字创建成功返回一个文件描述符 ,创建失败返回-1,同时错误码会被设置。
参数:
- domain:网络通信设置为AF_INET(IPv4)或AF_INET6(IPv6);
- type:基于UDP的网络通信,我们采用的就是SOCK_DGRAM,叫做用户数据报服务;
- protocol:创建套接字的协议类别,一般设置为0;
struct sockaddr_in 结构体:
struct sockaddr_in当中的成员如下:
sin_family:表示通信机制(本地/网络)。
sin_port:表示端口号,是一个16位的整数。
sin_addr.s_addr:表示IP地址,是一个32位的整数。
bind:绑定端口号:
// 绑定端口号 (TCP/UDP, 服务器)
int bind(int socket, const struct sockaddr *address, socklen_t address_len);
返回值:
- 绑定成功返回0,绑定失败返回-1,同时错误码会被设置。
参数:
- socket:绑定的文件的文件描述符。也就是我们创建套接字时获取到的文件描述符。
- addr:网络相关的属性信息,包括协议家族、IP地址、端口号等。
- addrlen:传入的addr结构体的长度。
读取数据:recvfrom函数
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
返回值:
- 读取成功返回实际读取到的字节数,读取失败返回-1,同时错误码会被设置。
参数:
- sockfd:对应操作的文件描述符。表示从该文件描述符索引的文件当中读取数据。
- buf:读取数据的存放位置。
- len:期望读取数据的字节数。
- flags:读取的方式。一般设置为0,表示阻塞读取。
- src_addr:对端网络相关的属性信息,包括协议家族、IP地址、端口号等。
- addrlen:调用时传入期望读取的src_addr结构体的长度,返回时代表实际读取到的src_addr结构体的长度,这是一个输入输出型参数。
注意:
- 由于recvfrom函数提供的参数也是struct sockaddr类型的,因此我们在传入结构体地址时需要将struct sockaddr_in类型进行强转。
发送数据:sendto函数
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
返回值:
- 写入成功返回实际写入的字节数,写入失败返回-1,同时错误码会被设置。
参数:
- sockfd:对应操作的文件描述符。表示将数据写入该文件描述符索引的文件当中。
- buf:待写入数据的存放位置。
- len:期望写入数据的字节数。
- flags:写入的方式。一般设置为0,表示阻塞写入。
- dest_addr:对端网络相关的属性信息,包括协议家族、IP地址、端口号等。 addrlen:传入dest_addr结构体的长度。
2. C/S 回声模拟
结果演示:
源代码:
- makefile
.PHONY:all
all:udp_server udp_client
udp_server:udp_server.cc
g++ -o $@ $^ -std=c++11
udp_client:udp_client.cc
g++ -o $@ $^ -std=c++11 -static
.PHONY:clean
clean:
rm -f udp_server udp_client
- udp_server.cc
#include <iostream>
#include <string>
#include <cerrno>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
using namespace std;
int main()
{
//1.创建套接字
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if(sock < 0)
{
cout << "socket failed:" << errno << endl;
return 1;
}
//2.定义结构体
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(uint16_t(8080));
local.sin_addr.s_addr = INADDR_ANY;
//3.绑定端口号
if(bind(sock, (struct sockaddr*)&local, sizeof(local)) <0 )
{
cout<< "bind failed:" << errno << endl;
return 2;
}
//4.通信
while(true)
{
char buffer[1024];
struct sockaddr_in peer;
socklen_t len = sizeof(peer);
recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr*)&peer, &len);
cout<< "client say # "<< buffer <<endl;
string message = "hello client";
sendto(sock, message.c_str(), message.size(), 0, (struct sockaddr*)&peer, len);
}
return 0;
}
- udp_client.cc
#include <iostream>
#include <string>
#include <cerrno>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
using namespace std;
//使用手册
void Usage(char* proc)
{
cout << "Usage:\n\t" << proc <<" server_ip server_port"<<endl;
}
int main(int argc, char* argv[])
{
if(argc!=3)
{
Usage(argv[0]);
return 1;
}
//1.创建套接字
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if(sock < 0)
{
cout << "socket failed:" << errno <<endl;
return 2;
}
//2.定义结构体
struct sockaddr_in server;
socklen_t len = sizeof(server);
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr(argv[1]);
server.sin_port = htons(atoi(argv[2]));
//客户端不用显示绑定
//3.通信
while(true)
{
string message;
char buffer[1024];
cout << "请输入:";
cin >> message;
sendto(sock, message.c_str(), message.size(), 0, (struct sockaddr*)&server, len);
recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr*)&server, &len);
cout << "server say # " << buffer<<endl;
}
return 0;
}
3. C/S myshell 的制作
结果演示:
源代码:
- makefile
.PHONY:all
all:udp_server udp_client
udp_server:udp_server.cc
g++ -o $@ $^ -std=c++11
udp_client:udp_client.cc
g++ -o $@ $^ -std=c++11
.PHONY:clean
clean:
rm -f udp_server udp_client
- udp_server.cc
#include <iostream>
#include <string>
#include <cerrno>
#include <cstring>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
using namespace std;
//使用手册
void Usage(char* proc)
{
cout<<"Usage:\n\t"<<proc<<" server_port"<<endl;
}
int main(int argc, char* argv[])
{
if(argc!=2)
{
Usage(argv[0]);
return 1;
}
//1.创建套接字
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if(sock<0)
{
cout<<"socket failed!"<<errno<<endl;
return 2;
}
//2.定义结构体
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_addr.s_addr = INADDR_ANY;
local.sin_port = htons(atoi(argv[1]));
//3.绑定
if(bind(sock, (struct sockaddr*)&local, sizeof(local))<0)
{
cout << "bind failed!"<<errno<<endl;
return 3;
}
//4.业务逻辑
while(true)
{
char buffer[1024]={0};
struct sockaddr_in peer;
socklen_t len = sizeof(peer);
ssize_t s = recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr*)&peer, &len);
if(s>0)
{
buffer[s]=0;
cout<<"client say # " << buffer;
//popen函数:执行buffer里的命令,将执行结果以文件方式返回
FILE* fd = popen(buffer, "r");
char line[1024];
string message;
while(fgets(line, sizeof(line),fd)!=NULL)
{
message += line;
}
sendto(sock, message.c_str(), message.size(), 0, (struct sockaddr*)&peer, len);
}
}
return 0;
}
- udp_client.cc
#include <iostream>
#include <string>
#include <cerrno>
#include <cstring>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
using namespace std;
//使用手册
void Usage(char* proc)
{
cout << "Usage:\n\t"<<proc<<" server_ip server_port"<<endl;
}
int main(int argc, char* argv[])
{
if(argc!=3)
{
Usage(argv[0]);
return 1;
}
//1.创建套接字
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if(sock<0)
{
cout << "socket failed:" <<errno<<endl;
return 2;
}
//2.定义结构体
struct sockaddr_in server;
socklen_t len = sizeof(server);
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr(argv[1]);
server.sin_port = htons(atoi(argv[2]));
//客户端不用显示绑定
//3.业务逻辑
while(true)
{
cout<<"My shell # ";
char buffer[1024]={0};
fgets(buffer, sizeof(buffer), stdin);
sendto(sock, buffer, sizeof(buffer), 0, (struct sockaddr*)&server, len);
ssize_t s = recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr*)&server, &len);
if(s>0)
{
buffer[s]=0;
cout<<buffer<<endl;
}
}
return 0;
}
如果上述文章对您有所帮助的话,还请点赞👍,收藏😉,关注🎈