From b6441a19e4db6339e37de3440107be0530c5baaf Mon Sep 17 00:00:00 2001
From: houxiao <houxiao@454eff88-639b-444f-9e54-f578c98de674>
Date: 星期四, 20 四月 2017 15:09:10 +0800
Subject: [PATCH] socket server finished

---
 FaceServer/ev_server.cpp |  143 +++++++++++++++++++++++++++++++----------------
 1 files changed, 94 insertions(+), 49 deletions(-)

diff --git a/FaceServer/ev_server.cpp b/FaceServer/ev_server.cpp
index 4d5b29c..ce9ebb1 100644
--- a/FaceServer/ev_server.cpp
+++ b/FaceServer/ev_server.cpp
@@ -9,6 +9,8 @@
 
 #include <sys/time.h>
 
+#include <netinet/tcp.h> // for TCP_NODELAY
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -32,12 +34,14 @@
 	size_t recvbuff_end;
 	size_t recvbuff_max;
 	size_t read_times; // read times for a command
+	bool toClose;
 	
 	evclient_proc_t proc;
 	
 	EVClient() : 
 		fd(-1), buf_ev(nullptr), 
 		recvbuff(nullptr), recvbuff_end(0), recvbuff_max(0), read_times(0), 
+		toClose(false), 
 		proc(nullptr)
 	{ }
 };
@@ -47,6 +51,12 @@
 #endif
 
 // Set a socket to non-blocking mode.
+static int setnodelay(int fd)
+{
+	int flag = 1; 
+	return setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
+}
+
 static int setnonblock(int fd)
 {
 	int flags;
@@ -59,6 +69,15 @@
 		return -1;
 
 	return 0;
+}
+
+static int setlinger(int fd)
+{
+	struct linger so_linger;
+	so_linger.l_onoff = 1;
+	so_linger.l_linger = 0;
+	
+	return setsockopt(fd, SOL_SOCKET, SO_LINGER, &so_linger, sizeof(so_linger));
 }
 
 // Called by libevent when there is an error on the underlying socket descriptor.
@@ -99,48 +118,47 @@
 	EVPHeader* evpHeader = (EVPHeader*)client->recvbuff;
 	
 	// read header if expected
+	if (client->recvbuff_end == 0)
 	{
 		uint8_t headerBuff[sizeof(EVPHeader)];
-		if (client->recvbuff_end == 0)
+
+		size_t readSize = bufferevent_read(bufev, headerBuff, sizeof(headerBuff));
+		client->read_times = 1;
+		if (readSize != sizeof(headerBuff))
 		{
-			size_t readSize = bufferevent_read(bufev, headerBuff, sizeof(headerBuff));
-			client->read_times = 1;
-			if (readSize != sizeof(headerBuff))
-			{
-				LOG_WARN << "client send incomplete header" << LOG_ENDL;
-				buffered_on_error(bufev, 0, arg);
-				return;
-			}
-			
-			evpHeader = (EVPHeader*)headerBuff;
-			
-			// check header
-			if (evpHeader->proto <= EVPProto::EVPP__FIRST || evpHeader->proto >= EVPProto::EVPP__LAST || 
-				evpHeader->cmd <= EVPCommand::EVPC__FIRST || evpHeader->cmd >= EVPCommand::EVPC__LAST || 
-				evpHeader->size < sizeof(EVPHeader) || evpHeader->size > CLIENT_BUFFER_MAX)
-			{
-				LOG_WARN << "client send invalid header" << LOG_ENDL;
-				buffered_on_error(bufev, 0, arg);
-				return;
-			}
-			
-			if (client->recvbuff_max < evpHeader->size)
-			{
-				delete[] client->recvbuff;
-				client->recvbuff = nullptr;
-				client->recvbuff_max = 0;
-			}
-			
-			if (client->recvbuff == nullptr)
-			{
-				uint32_t _CLIENT_BUFFER_MAX = CLIENT_BUFFER_MAX;
-				client->recvbuff_max = std::min(evpHeader->size, _CLIENT_BUFFER_MAX);
-				client->recvbuff = new uint8_t[client->recvbuff_max];
-			}
-			
-			memcpy(client->recvbuff, headerBuff, sizeof(headerBuff));
-			client->recvbuff_end = sizeof(headerBuff);
+			LOG_WARN << "client send incomplete header" << LOG_ENDL;
+			buffered_on_error(bufev, 0, arg);
+			return;
 		}
+		
+		evpHeader = (EVPHeader*)headerBuff;
+		
+		// check header
+		if (evpHeader->proto <= EVPProto::EVPP__FIRST || evpHeader->proto >= EVPProto::EVPP__LAST || 
+			evpHeader->cmd <= EVPCommand::EVPC__FIRST || evpHeader->cmd >= EVPCommand::EVPC__LAST || 
+			evpHeader->size < sizeof(EVPHeader) || evpHeader->size > CLIENT_BUFFER_MAX)
+		{
+			LOG_WARN << "client send invalid header" << LOG_ENDL;
+			buffered_on_error(bufev, 0, arg);
+			return;
+		}
+		
+		if (client->recvbuff_max < evpHeader->size)
+		{
+			delete[] client->recvbuff;
+			client->recvbuff = nullptr;
+			client->recvbuff_max = 0;
+		}
+		
+		if (client->recvbuff == nullptr)
+		{
+			uint32_t _CLIENT_BUFFER_MAX = CLIENT_BUFFER_MAX;
+			client->recvbuff_max = std::min(evpHeader->size, _CLIENT_BUFFER_MAX);
+			client->recvbuff = new uint8_t[client->recvbuff_max];
+		}
+		
+		memcpy(client->recvbuff, headerBuff, sizeof(headerBuff));
+		client->recvbuff_end = sizeof(headerBuff);
 	}
 	
 	// read sub command or data
@@ -159,33 +177,37 @@
 	if (evpHeader->size == client->recvbuff_end)
 	{
 		// call client proc
-		bool closeClient = true;
 		if (client->proc != nullptr)
 		{
 			EVClientStub cs(client->recvbuff, client->recvbuff_end);
 			cs.id = client->fd;
-			closeClient = !(client->proc(cs));
+			client->toClose = !(client->proc(cs));
 			
 			if (cs.sendBuff != nullptr && cs.sendBuffSize > 0)
 			{
 				size_t writeSize = bufferevent_write(bufev, cs.sendBuff, cs.sendBuffSize);
-				if (writeSize != cs.sendBuffSize)
-					LOG_WARN << "server send truncate " << (cs.sendBuffSize - writeSize) << " bytes" << LOG_ENDL;
-				
+				bufferevent_enable(client->buf_ev, EV_WRITE);
+				if (writeSize != 0)
+					LOG_WARN << "server send truncate" << LOG_ENDL;
+
 				if (cs.deleteSendBuff)
+				{
 					delete[] cs.sendBuff;
+					cs.sendBuff = nullptr;
+				}
 			}
-		}
-		
-		if (closeClient)
-		{
-			LOG_DEBUG << "server initiative close" << LOG_ENDL;
-			buffered_on_error(bufev, 0, arg);
 		}
 
 		// reset client
 		client->recvbuff_end = 0;
 		client->read_times = 0;
+	}
+	else
+	{
+		LOG_WARN << "recvbuff incomplete, evpHeader.size=" << evpHeader->size 
+			<< ", recvbuff_end=" << client->recvbuff_end 
+			<< ", read_times=" << client->read_times 
+			<< LOG_ENDL;
 	}
 	
 	// check read times
@@ -200,6 +222,23 @@
 // We only provide this because libevent expects it, but we don't use it.
 static void buffered_on_write(struct bufferevent *bufev, void *arg)
 {
+	struct EVClient *client = (struct EVClient *)arg;
+	if (evbuffer_get_length(bufev->output) == 0)
+	{
+		bufferevent_disable(client->buf_ev, EV_WRITE);
+		if (client->toClose)
+		{
+			LOG_DEBUG << "server initiative close" << LOG_ENDL;
+			buffered_on_error(bufev, 0, arg);
+		}
+		else
+		{
+			//bufferevent_flush(bufev, EV_WRITE, BEV_FLUSH);//#todo not work
+			//bufferevent_flush(bufev, EV_WRITE, BEV_FINISHED);
+			// flush socket
+			shutdown(client->fd, SHUT_WR);
+		}
+	}
 }
 
 // This function will be called by libevent when there is a connection ready to be accepted.
@@ -217,6 +256,12 @@
 	// Set the client socket to non-blocking mode.
 	if (setnonblock(client_fd) < 0)
 		LOG_WARN << "failed to set client socket non-blocking" << LOG_ENDL;
+	
+	if (setnodelay(client_fd) < 0)
+		LOG_WARN << "failed to set client socket no-delay" << LOG_ENDL;
+	
+	//if (setlinger(client_fd) < 0)
+	//	LOG_WARN << "failed to set client socket linger" << LOG_ENDL;
 
 	// We've accepted a new client, create a client object.
 	struct EVClient* client = new EVClient;

--
Gitblit v1.8.0