CS模型的核心精要
1、服务端编程初体验
1.1、客户端/服务端编程模式
- 服务端长期暴露网络,并等待客户端连接
- 客户端发起连接动作,并等待服务端回应
- 特点:
- 服务端无法主动连接客户端
- 客户端只能按照预定义的方式连接服务端
1.2、服务端编程模式
- 准备网络连接
- 绑定端口
- 进入端口监听状态
- 等待连接
1.3、服务端核心工作:绑定&监听&接收
- 绑定
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
- 监听
int listen(int sockfd, int backlog);
- 接收
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
1.4、深度剖析服务端
- 服务端socket只用于接收连接,不进行实际通信
- 当接收到连接时,
accpet()
函数返回与客户端通信的socket - 服务端
socket
产生用于通信的客户端socket
- 所以,
socket
究竟是什么玩意?如何理解?
1.5、深度理解socket()
函数
socket()
是什么?socket()
是一个“多功能”函数
socket()
返回的又是什么?socket()
的返回值是用于通信的资源标识符
socket()
还能做什么?socket()
可提供不同类型的通信功能(本地进程间通信)
1.6、服务端编程示例
//2-2.c
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
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 err\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 err\n");
return -1;
}
if( listen(server,1) == -1 )
{
printf("listen err\n");
return -1;
}
printf("server start success\n");
asize = sizeof(caddr);
client = accept(server,(struct sockaddr*)&caddr, &asize);
if(client == -1)
{
printf("client accept err\n");
return -1;
}
printf("client : %d\n", client);
do
{
int i = 0;
r = recv(client, buf, sizeof(buf), 0);
if( r > 0)
{
len += r;
}
for( i = 0; i < r; i++)
{
printf("%c",buf[i]);
}
} while ( len < 64);
printf("\n");
send(client, "hello world!", 12, 0);
sleep(1);
close(client);
close(server);
return 0;
}
1.7、客户端/服务端编程的核心模式
- 服务端长时间运行(死循环)接收客户端请求
- 客户端连接后向服务端发送请求(协议数据)
- 服务端核心编程模式
- 客户端/服务端编程的核心模式
1.8、编程实验
- 服务端持续监听客户端连接
- 服务端被连接后echo客户端数据
- 服务端接收到quit后断开连接
- 客户端接收用户输入并发送到服务端
//client.c
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<stdio.h>
#include<unistd.h>
#include<string.h>
int main()
{
int sock = 0;
struct sockaddr_in addr = {0};
int len = 0;
int r = 0;
char buf[128] = {0};
char input[32] = {0};
sock = socket(PF_INET,SOCK_STREAM,0);
if(sock == -1)
{
printf("socket err\n");
return -1;
}
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("192.168.252.223");
addr.sin_port = htons(8888);
if(connect(sock,(struct sockaddr*)&addr,sizeof(addr)) == -1)
{
printf("connect err\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("Recv : %s\n", buf);
}
else
{
break;
}
}
close(sock);
return 0;
}
//server.c
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
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 err\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 err\n");
return -1;
}
if( listen(server,1) == -1 )
{
printf("listen err\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 err\n");
return -1;
}
printf("client : %d\n", client);
do
{
r = recv(client, buf, sizeof(buf), 0);
if( r > 0)
{
printf("Recv: %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;
}
1.9、思考
如何增强服务端能力,同时支持多个客户端?