Tcpserver_learn

最近都在学习Tcp的网络编程,从编写一个简单的Tcpserver到使用select、poll、epoll来提高服务器处理的能力,了解了许多,觉得有必要进行一个简单的总结

想要学习Tcpserver需要进行一些简单的练习,这里给出一些源码,希望能对你有所帮助https://github.com/ershengaaa/Tcpserver_learn ,觉得有用的同学可以给个star

1. 常用头文件

在这里仅列出一些初学时比较常用的头文件

#include <stdio.h>    //c语言头文件
#include <stdlib.h>
#include <string.h>  //对字符串的处理,处理发送消息及接受消息
#include <sys/types.h> //数据类型定义
#include <sys/socket.h> //提供socket函数及数据结构
#include <sys/wait.h>  //提供进程等待,进程间通讯及共享内存的函数
#include <errno.h>    //用于错误处理
#include <netinet/in.h>  //定义数据结构sockaddr_in,协议地址
#include <arpa/inet.h>  //提供IP地址转换函数
#include <unistd.h>     //提供通用的文件,目录,程序及进程操作的函数
#include <poll.h>      //提供poll函数及pollfd集合
#include <sys/epoll.h>  //提供epoll函数

2. 编写思路

  • 首先,不管使用何种方法,其服务端的创建socket绑定socket监听这几步,客户端创建socket发起连接一般都是必需的:
//server.vpp
int listenfd;
struct sockaddr_in servaddr;   //ipv4 
char buff[4096];
int n;

if ( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {  //创建socket 
	printf("creat socket error: %s(errno: %d)\n", strerror(errno), errno);
	return 0;
}
//初始化协议地址 
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(6666);

if ( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1) { //绑定socket和端口号 
	printf("bind socket error: %s(errno: %d)\n", strerror(errno), errno);
	return 0;
}

if ( listen(listenfd, 10) == -1) {  //监听端口号 
	printf("listen socket error: %s(errno: %d)\n", strerror(errno), errno);
	return 0;
}
//client.cpp
int sockfd, n;
char recvline[4096], sendline[4096];
struct sockaddr_in servaddr;   //ipv4 
if (argc != 2) {
	printf("usage: ./client <ipaddress>\n");
	return 0;
}

if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {  //创建socket 
	printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);
	return 0;
}
//初始化协议地址 
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(6666);
if ( inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0) {  //转换字符串到网络地址 
	printf("inet_pton error for %s\n", argv[1]);
	return 0;
}

if (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) {  //连接指定计算机的端口 
	printf("connect error: %s(errno: %d)\n", strerror(errno), errno);
	return 0;
}
  • 然后服务端大概就是一些特有变量的定义,再进行循环处理(这里以select进行服务端处理为例):
fd_set client_fdset;  	//监听文件描述符集合 
int maxsock;     		//监听文件描述符中最大的文件号 
struct timeval tv; 		 //设置超时时间 
int client_sockfd[5]; 	 //存放活动的sockfd 
bzero((void *)client_sockfd, sizeof(client_sockfd));
int conn_amount = 0;   	//用来记录文件描述符集合 
maxsock = serverfd;   
char buffer[1024];
int ret = 0;
while (1) {  //循环处理 
	/* 初始化文件描述符集合以及添加服务器描述符 */
	/* 轮询各个描述符 */
	/* 将新连接加入到集合中,并进行接受/发送消息处理 */
	/* 关闭所有连接的客户 */
}
/* 关闭socket */
  • 客户端相对来说就比较简单了,就连接建立之后向服务端发送消息,如果需要发送多个消息可以用while(1)循环处理:
char buffer[1024];
bzero(buffer, sizeof(buffer));
recv(connfd, buffer, 1024, 0);
printf("recv: %s\n", buffer);
bzero(buffer, sizeof(buffer));
strcpy(buffer, "this is client!\n");
send(connfd, buffer, 1024, 0);
while (1) {
		/* 输入想要发送的信息 */
		/* send函数发送,有时recv服务端的回信 */
}
/* 关闭socket */
  • 最后编写makefile,对于这样只有两个文件的服务端与客户端,以下makefile可以通用:
all: server client;
server : server.o
	g++ -g -o server server.o
client : client.o
	g++ -g -o client client.o
server.o : server.cpp
	g++ -g -c server.cpp
client.o : client.cpp
	g++ -g -c client.cpp
clean : all
	rm -f server client *.o

源码链接 https://github.com/ershengaaa/Tcpserver_learn ,个人水平有限,如有错误还望指出!!!

select、poll、epoll的区别

select、poll、epoll三者都是多路IO复用的机制。多路IO复用就通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读或写就绪),能够通知程序进行相应的读写操作,但三者本质上仍是同步IO。异步IO不需要自己进行读、写处理,异步IO的实现会负责把数据从内核拷贝到用户空间

  • select与poll–>一般认为poll()比select()高级

1.poll()不要求开发者在计算最大文件描述符时进行+1的操作

2.poll()在应对大数目的文件描述符的时候速度更快,因为对于select()来说内核需要检查大量描述符对应的fd_set中的每一位比特位,比较费事

3.select()可以监控的文件描述符数目是固定的,相对来说也较少。而对于poll来说,可以创建特定大小的数组来保存监控的描述符,而不受文件描述符值大小的影响,而且poll可以监控的文件数目远大于select()

4.对于select来说,其监控的fd_set在select返回后会变化,所以在下一次进入select()之前都需要重新初始化

5.每次在超时后在下一次进入到select()之前都需要重新设定

  • select()的优点

1.select()的可移植性更好

2.select()对于超时值提供了更好的精度

  • epoll的优点

1.支持一个进程打开大数目的socket描述符(FD)

2.IO效率不随FD数目增加而下降

3.使用mmap加速内核与用户空间的消息传递

----------------------------------------------分享今日happy-------------------------------------------

在重邮的第三个冬天,终于盼来了一场大雪,虽然转瞬即逝,但对于我来说足以!!!

分享一首最近特别喜欢的一首歌:Heathens

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值