客户端/服务端 编程模式
- 服务端长期保留于网络(公开自己的 IP 地址),并等待客户端连接
- 客户端发起连接动作,并等待服务端回应
- 特点:
- 服务端无法主动连接客户端
- 客户端只能按照预定义的方式(协议)连接服务端
1. 准备网络连接
2. 绑定端口
3. 进入端口监听状态
4. 等待连接
文章图片
服务端核心工作:绑定 & 监听 & 接收
- 绑定:
int bind(int sock, struct sockaddr *addr, socklen_t addrlen);
- 监听:
int listen(int sock, int backlog);
- 接收:
int accept(int sock, struct sockaddr *addr, socklen_t addrlen);
- 服务端 socket 只用于接收连接,不进行实际通讯
- 当接收到连接时,accept() 函数返回与客户端通信的 socket
- 服务端 socket 产生用于通讯的客户端 socket
所以,socket 究竟是什么玩意?如何理解?深入理解 socket() 函数
- socket() 是什么?
- socket() 是一个多功能函数
- socket() 返回的又是什么?
- socket() 的返回值是用于通讯的资源标识符
- socket() 还能做什么?
- socket() 可提供不同类型的通讯功能(本地进程间通讯)
#include
#include
#include
#include
#include
#include
#include int main()
{
int server = 0;
struct sockaddr_in saddr = {0};
int clinet = 0;
struct sockaddr_in caddr = {0};
socklen_t asize = 0;
int len = 0;
char buf[32] = {0};
int r = 0;
server = socket(PF_INET, SOCK_STREAM, 0);
if (server == -1) {
printf("server socket error\n");
return -1;
}saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
saddr.sin_port = htons(8899);
if (bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == -1) {
printf("server bind error\n");
return -1;
}if (listen(server, 1) == -1) {
printf("server listen error\n");
return -1;
}printf("server start success\n");
asize = sizeof(caddr);
clinet = accept(server, (struct sockaddr*)&caddr, &asize);
if (clinet == -1) {
printf("client accept error\n");
return -1;
}printf("client: %d\n", clinet);
len = 0;
do {
int i = 0;
r = recv(clinet, buf, sizeof(buf), 0);
if (r > 0) {
len += r;
}for (i=0;
i
客户端/服务端 编程的核心模式
- 服务端长时间运行(死循环)接收客户端的请求
- 客户端连接后向服务端发送请求(协议数据)
文章图片
服务端核心编程模式
文章图片
编程实验:客户端/服务端编程实验
- 服务端持续监听客户端连接
- 服务端被连接后 echo 客户端数据
- 服务端接收到 quit 后断开连接
- 客户端接收用户输入并发送到服务端
服务端
#include
#include
#include
#include
#include
#include
#include int main()
{
int server = 0;
struct sockaddr_in saddr = {0};
int client = 0;
struct sockaddr_in caddr = {0};
socklen_t asize = 0;
int len = 0;
char buf[32] = {0};
int r = 0;
server = socket(PF_INET, SOCK_STREAM, 0);
if (server == -1) {
printf("server socket error\n");
return -1;
}saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
saddr.sin_port = htons(8888);
if (bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == -1) {
printf("server bind error\n");
return -1;
}if (listen(server, 1) == -1) {
printf("server listen error\n");
return -1;
}printf("server start success\n");
while (1) {
asize = sizeof(caddr);
client = accept(server, (struct sockaddr*)&caddr, &asize);
if (client == -1) {
printf("client accept error\n");
return -1;
}printf("client: %d\n", client);
do {
r = recv(client, buf, sizeof(buf), 0);
if (r > 0) {
printf("Receive: %s\n", buf);
if (strcmp(buf, "quit") != 0) {
len = send(client, buf, r, 0);
}
else {
break;
}
}
} while (r > 0);
close(client);
}close(server);
return 0;
}
客户端
#include
#include
#include
#include
#include
#include
#include int main()
{
int sock = 0;
struct sockaddr_in addr = {0};
int len = 0;
char buf[128] = {0};
char input[32] = {0};
int r = 0;
sock = socket(PF_INET, SOCK_STREAM, 0);
if (sock == -1) {
printf("socket error\n");
return -1;
}addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("192.168.2.46");
addr.sin_port = htons(8888);
if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
printf("connect error\n");
return -1;
}printf("connect success\n");
while (1) {
printf("Input: ");
scanf("%s", input);
len = send(sock, input, strlen(input) + 1, 0);
r = recv(sock, buf, sizeof(buf), 0);
if (r > 0) {
printf("Receive: %s\n", buf);
}
else {
break;
}
}close(sock);
return 0;
}
思考:如何增强服务端能力,同时支持多个客户端?