最近都在学习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