008.一个简单的网络服务器开发----回声服务器

高性能服务器开发 专栏收录该内容
13 篇文章 0 订阅

目录

简单的回声服务器实现

项目需求

技术分析

博主相关的技术博客

网络编程之 socket编程

网络编程函数小总结与初识socket

网络编程之bind()的未解之谜

网络编程之 字节序和深入理解bind()函数

网络编程之 listen()函数的使用与三次握手的理解

socket编程之 accept函数的理解

socket编程之 connect()函数

基于 Linux 的文件操作 网络编程的最后一环

server.c

client.c

测试

增加需求


简单的回声服务器实现

项目需求

        实现回声服务器的客户端/服务器程序,客户端通过网络连接到服务器,并发送任意一串英文信息,服务器端接收信息后,将每个字符转换为大写并回送给客户端显示。

技术分析

  1. 网络字节序
  2. sockaddr数据结构
  3. ip地址转换函数
  4. socket函数
  5. bind函数
  6. listen函数
  7. accept函数
  8. connect函数
  9. write函数
  10. read函数

    网络通信与socket,这一部分博主以前做过详细的分析所以直接附上以前的博客链接了:以下链接均为作者--socket编程专栏文章。

博主相关的技术博客

 

        其实呢,你去看博主的网络编程专栏会发现就这这几天博主其实就写了一个回声服务器而且在那篇博客的基础上列举了一些大家写最基本的回声服务器会遇到的一些错误情况。因为本篇博客也是写回声服务器所以我会基于之前的那两篇博客来发挥,主要也就是增加一部分测试案例。

server.c

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<ctype.h>


#define SERVER_PORT 6666
#define	MAXLINE 100
int main(void) {

	/*定义  server端套接字文件描述符:sfd
				client套接字文件描述符:cfd
				read函数读取到的字符数:n */
	int sfd, cfd, n;

	/* server端地址定义(包含IP、PORT、协议族)暂未指定:server_addr
	   client端地址定义(包含IP、PORT、协议族)不需要再server.c定义,accept函数会自动填充*/
	struct sockaddr_in server_addr, client_addr;

	socklen_t  client_len;//为 accept函数第三个参数做准备
	char buf[MAXLINE];//接收client端发来的字符的缓冲区

	/*bzero:将server端置空,为了给后续的IP、PORT、协议族赋值所用
	 后续操作是为了 bind函数绑定IP、PORT和协议族的固定操作。*/
	bzero(&server_addr, sizeof(server_addr));
	server_addr.sin_family = AF_INET;//IPV4
	server_addr.sin_port = htons(SERVER_PORT);//转换为网络字节序
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

	sfd = socket(AF_INET, SOCK_STREAM, 0);	//调用 socket函数值后会返回一个文件描述符
	bind(sfd, (struct sockaddr*)&server_addr, sizeof(server_addr));	//绑定IP、PORT、协议族
	listen(sfd, 21);

	/* accept函数放在 while 里面和外面的结果是不一样的,
			accept放在while里面代表客户端只能和服务器端通信一次
			accept放在while外面那么客户端就可以一直和服务器进行通信
	*/
	while (1) {
		client_len = sizeof(client_addr);
		cfd = accept(sfd, (struct sockaddr*)&client_addr, &client_len);//accept调用和会给server端返回一个和client端连接好的socket。

		n = read(cfd, buf, MAXLINE);

		for (int i = 0; i < n; i++) {
			buf[i] = toupper(buf[i]);
		}

		write(cfd, buf, n);
		close(cfd);
	}

	return 0;

}

 

client.c

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<ctype.h>

#define SERVER_PORT 6666
#define MAXLINE 100
int main(void) {

	int sfd, n;
	struct sockaddr_in server_addr;
	char buf[MAXLINE];

	bzero(&server_addr, sizeof(server_addr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(SERVER_PORT);
	inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr);

	sfd = socket(AF_INET, SOCK_STREAM, 0);

	connect(sfd, (struct sockaddr*)&server_addr, sizeof(server_addr));

	while (1) {
		fgets(buf, sizeof(buf), stdin);
		write(sfd, buf, strlen(buf));

		n = read(sfd, buf, sizeof(buf));
		write(STDOUT_FILENO, buf, n);

	}
	close(sfd);

	return 0;

}

ssh1:

gcc server.cpp -o server

./server

 

ssh2:

gcc client.cpp -o client

./client
hello server.c

我们可以看到当启动 server端到结束时都没有任何东西(其实我们可以增加一些输出比如说显示客户端的ip地址或者端口号,甚至还可以将转换好的字符串输出数来,可以在后续的博客进行实现,本博客为了简便甚至没有加上出错处理函数,就为了突出整个程序的逻辑!!)

client端:当我们输入:hello server.c,,马上就能得到服务器返回给我们转成大写的字符串,可是当我们在输入字符串的时候服务器已经不理我们了,甚至还结束了我们的连接(原因是因为我们把close函数放在while循环里面的)。

 

测试

close放在while外会发生什么呢?

结果依旧是服务器只反应了我们的第一个字符串,又因为没有close函数关闭我们可以一直输入字符串,但是服务器都不会再进行响应了。

 

增加需求

        服务器和客户端通讯建立后服务器能够一直回响客服端发来的消息

技术实现:

        将accept函数放在while函数外面,再将close函数放在while函数外面即可。

代码对比:

实现效果:(改变代码之后记得要重新编译源cpp文件)

ssh1:

gcc server.cpp -o server
./server
 

ssh2:

./client

server端的结果和上面是一样的

 

 

感谢观看。

 

 

 

 

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:深蓝海洋 设计师:CSDN官方博客 返回首页

打赏作者

dearQiHao

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值