TCP_server
来源:互联网 发布:vb里的option 编辑:程序博客网 时间:2024/06/16 14:51
client.c(客户端)
#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/socket.h>#include <arpa/inet.h>#include <netinet/in.h>#include <string.h>void usage(const char* arg){ printf("%s [server_ip][server_port]\n",arg);}int main(int argc,char* argv[]){ if(argc != 3) { usage(argv[0]); return 1; } int sock=socket(AF_INET,SOCK_STREAM,0); if(sock < 0) { perror("socket:"); exit(2); } struct sockaddr_in client; client.sin_family = AF_INET; client.sin_port = htons(atoi(argv[2])); client.sin_addr.s_addr = inet_addr(argv[1]); char buf[1024]; if(connect(sock,(struct sockaddr*)&client,sizeof(client)) == 0) { while(1) { printf("Please Enter:"); fflush(stdout); ssize_t size = read(0,buf,sizeof(buf)-1); if(size > 0) { buf[size]=0; write(sock,buf,strlen(buf)); size = read(sock,buf,sizeof(buf)-1); buf[size]=0; printf("%s",buf); } else if(size == 0) { printf("server quit"); break; } else { perror("read"); break; } } } return 0;}
单用户server
#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/socket.h>#include <arpa/inet.h>#include <netinet/in.h>#include <string.h>#include <pthread.h>void usage(const char* arg){ printf("%s[ip][port]\n",arg);}int getsock(const char* _ip,const char* _port){ int sock = socket(AF_INET,SOCK_STREAM,0); if(sock<0) { perror("socket"); exit(1); } struct sockaddr_in server; server.sin_family = AF_INET; server.sin_port = htons(atoi(_port)); server.sin_addr.s_addr = inet_addr(_ip); if(bind(sock,(struct sockaddr*)&server,sizeof(server)) < 0) { perror("bind:"); exit(2); } if(listen(sock,5)<0) { perror("listen"); exit(3); } return sock;}int main(int argc,char* argv[]){ if(argc!=3) { usage(argv[0]); return 1; } int sock=getsock(argv[1],argv[2]); while(1) { struct sockaddr_in server; socklen_t len=sizeof(server); int new_sock = accept(sock,(struct sockaddr*)&server,&len); if(new_sock<0) { perror("accept:"); continue; } char buf[1024]; printf("wait client...\n"); while(1) { ssize_t size=read(new_sock,buf,sizeof(buf)-1); if(size<0) { close(new_sock); perror("read:"); break; } else if(size == 0) { close(new_sock); printf("client is quit...\n"); break; } else { buf[size]=0; printf("%s",buf); write(new_sock,buf,strlen(buf)); } } } return 0;}
多进程server
#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/socket.h>#include <arpa/inet.h>#include <netinet/in.h>#include <string.h>#include <pthread.h>void usage(const char* arg){ printf("%s[ip][port]\n",arg);}int getsock(const char* _ip,const char* _port){ int sock = socket(AF_INET,SOCK_STREAM,0); if(sock<0) { perror("socket"); exit(1); } struct sockaddr_in server; server.sin_family = AF_INET; server.sin_port = htons(atoi(_port)); server.sin_addr.s_addr = inet_addr(_ip); if(bind(sock,(struct sockaddr*)&server,sizeof(server)) < 0) { perror("bind:"); exit(2); } if(listen(sock,5)<0) { perror("listen"); exit(3); } return sock;}int main(int argc,char* argv[]){ if(argc!=3) { usage(argv[0]); return 1; } int sock=getsock(argv[1],argv[2]); while(1) { struct sockaddr_in server; socklen_t len=sizeof(server); int new_sock = accept(sock,(struct sockaddr*)&server,&len); if(new_sock<0) { perror("accept:"); continue; } pid_t id = fork(); if(id < 0) { perror("fork"); exit(4); } else if(id == 0) { pid_t pid=fork(); //再次fork退出父进程子进程变为孤儿进程由init进程回收原父进程不必等待子进程退出回收子进程 if(pid>0) { exit(6); } char buf[1024]; printf("wait client...\n"); while(1) { ssize_t size=read(new_sock,buf,sizeof(buf)-1); if(size<0) { close(new_sock); perror("read:"); break; } else if(size == 0) { close(new_sock); printf("client is quit...\n"); break; } else { buf[size]=0; printf("%s",buf); write(new_sock,buf,strlen(buf)); } } } else { close(new_sock); } } return 0;}
多线程server
#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/socket.h>#include <arpa/inet.h>#include <netinet/in.h>#include <string.h>#include <pthread.h>void usage(const char* arg){ printf("%s[ip][port]\n",arg);}int getsock(const char* _ip,const char* _port){ int sock = socket(AF_INET,SOCK_STREAM,0); if(sock<0) { perror("socket"); exit(1); } struct sockaddr_in server; server.sin_family = AF_INET; server.sin_port = htons(atoi(_port)); server.sin_addr.s_addr = inet_addr(_ip); if(bind(sock,(struct sockaddr*)&server,sizeof(server)) < 0) { perror("bind:"); exit(2); } if(listen(sock,5)<0) { perror("listen"); exit(3); } return sock;}void* service(void* arg){ char buf[1024]; int new_sock = (int)arg; printf("wait client...\n"); while (1) { ssize_t size = read(new_sock, buf, sizeof(buf) - 1); if (size < 0) { close(new_sock); perror("read:"); break; } else if (size == 0) { close(new_sock); printf("client is quit...\n"); break; } else { buf[size] = 0; printf("%s", buf); write(new_sock, buf, strlen(buf)); } }}int main(int argc,char* argv[]){ if(argc!=3) { usage(argv[0]); return 1; } int sock=getsock(argv[1],argv[2]); while(1) { struct sockaddr_in server; socklen_t len=sizeof(server); int new_sock = accept(sock,(struct sockaddr*)&server,&len); if(new_sock<0) { perror("accept:"); continue; } pthread_t id; pthread_create(&id,NULL,service,(void*)new_sock); pthread_detach(id);//设置为线程分离不必回收线程退出状态 } return 0;}
内存池
平常我们使用new、malloc在堆区申请一块内存,但由于每次申请的内存大小不一样就会产生很多内存碎片,造成不好管理与浪费的情况。
内存池则是在真正使用内存之前,先申请分配一定数量的、大小相等(一般情况下)的内存块留作备用。当有新的内存需求时,就从内存池中分出一部分内存块,若内存块不够再继续申请新的内存。这样做的一个显著优点是尽量避免了内存碎片,使得内存分配效率得到提升。
进程池&&线程池
这两个问题有一定的相似度,在面向对象程序编程中,对象的创建与析构都是一个较为复杂的过程,较费时间,所以为了提高程序的运行效率尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁。
所以我们可以创建一个进程池(线程池),预先放一些进程(线程)进去,要用的时候就直接调用,用完之后再把进程归还给进程池,省下创建删除进程的时间,不过当然就需要额外的开销了。
利用线程池与进程池可以使管理进程与线程的工作交给系统管理,不需要程序员对里面的线程、进程进行管理。
线程池主要用于
1、需要大量的线程来完成任务,且完成任务的时间比较短。 WEB服务器完成网页请求这样的任务,使用线程池技术是非常合适的。因为单个任务小,而任务数量巨大,你可以想象一个热门网站的点击次数。但对于长时间的任务,比如一个Telnet连接请求,线程池的优点就不明显了。因为Telnet会话时间比线程的创建时间大多了。
2、对性能要求苛刻的应用,比如要求服务器迅速响应客户请求。
3、接受突发性的大量请求,但不至于使服务器因此产生大量线程的应用。突发性大量客户请求,在没有线程池情况下,将产生大量线程,虽然理论上大部分操作系统线程数目最大值不是问题,短时间内产生大量线程可能使内存到达极限,并出现"OutOfMemory"的错误。
线程池优点
首先说一下多线程的好处:多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。
我们知道应用程序创建一个对象,然后销毁对象是很耗费资源的。创建线程,销毁线程,也是如此。因此,我们就预先生成一些线程,等到我们使用的时候在进行调度,于是,一些"池化资源"技术就这样的产生了。
本文所提到服务器程序是指能够接受客户请求并能处理请求的程序,而不只是指那些接受网络客户请求的网络服务器程序。
多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。但如果对多线程应用不当,会增加对单个任务的处理时间。可以举一个简单的例子:
假设在一台服务器完成一项任务的时间为T
T1 创建线程的时间
T2 在线程中执行任务的时间,包括线程间同步所需时间
T3 线程销毁的时间
显然T = T1+T2+T3。注意这是一个极度简化的假设。
可以看出T1,T3是多线程本身的带来的开销,我们渴望减少T1,T3所用的时间,从而减少T的时间。但一些线程的使用者并没有注意到这一点,所以在程序中频繁的创建或销毁线程,这导致T1和T3在T中占有相当比例。显然这是突出了线程的弱点(T1,T3),而不是优点(并发性)。
线程池技术正是关注如何缩短或调整T1,T3时间的技术,从而提高服务器程序性能的。它把T1,T3分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理客户请求时,不会有T1,T3的开销了。
线程池不仅调整T1,T3产生的时间段,而且它还显著减少了创建线程的数目。在看一个例子:
假设一个服务器一天要处理50000个请求,并且每个请求需要一个单独的线程完成。我们比较利用线程池技术和不利于线程池技术的服务器处理这些请求时所产生的线程总数。在线程池中,线程数一般是固定的,所以产生线程总数不会超过线程池中线程的数目或者上限(以下简称线程池尺寸),而如果服务器不利用线程池来处理这些请求则线程总数为50000。一般线程池尺寸是远小于50000。所以利用线程池的服务器程序不会为了创建50000而在处理请求时浪费时间,从而提高效率。
线程池的简单实现
#ifndef __THREAD_H #define __THREAD_H #include <vector> #include <string> #include <pthread.h> using namespace std; /** * 执行任务的类,设置任务数据并执行 */ class CTask { protected: string m_strTaskName; /** 任务的名称 */ void* m_ptrData; /** 要执行的任务的具体数据 */ public: CTask(){} CTask(const string& taskName) { m_strTaskName = taskName; m_ptrData = NULL; } virtual ~CTask(){} virtual int Run() = 0; void SetData(void* data); /** 设置任务数据 */ }; /** * 线程池管理类的实现 */ class CThreadPool { private: static vector<CTask*> m_vecTaskList; /** 任务列表 */ static bool shutdown; /** 线程退出标志 */ int m_iThreadNum; /** 线程池中启动的线程数 */ pthread_t *pthread_id; static pthread_mutex_t m_pthreadMutex; /** 线程同步锁 */ static pthread_cond_t m_pthreadCond; /** 线程同步的条件变量 */ protected: static void* ThreadFunc(void * threadData); /** 新线程的线程回调函数 */ static int MoveToIdle(pthread_t tid); /** 线程执行结束后,把自己放入到空闲线程中 */ static int MoveToBusy(pthread_t tid); /** 移入到忙碌线程中去 */ int Create(); /** 创建线程池中的线程 */ public: CThreadPool(int threadNum = 10); int AddTask(CTask *task); /** 把任务添加到任务队列中 */ int StopAll(); /** 使线程池中的线程退出 */ int getTaskSize(); /** 获取当前任务队列中的任务数 */ }; #endifThread.cpp
#include "Thread.h" #include <iostream> #include "stdlib.h" void CTask::SetData(void * data) { m_ptrData = data; } vector<CTask*> CThreadPool::m_vecTaskList; //任务列表 bool CThreadPool::shutdown = false; pthread_mutex_t CThreadPool::m_pthreadMutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t CThreadPool::m_pthreadCond = PTHREAD_COND_INITIALIZER; /** * 线程池管理类构造函数 */ CThreadPool::CThreadPool(int threadNum) { this->m_iThreadNum = threadNum; cout << "I will create " << threadNum << " threads" << endl; Create(); } /** * 线程回调函数 */ void* CThreadPool::ThreadFunc(void* threadData) { pthread_t tid = pthread_self(); while (1) { pthread_mutex_lock(&m_pthreadMutex); while (m_vecTaskList.size() == 0 && !shutdown) { pthread_cond_wait(&m_pthreadCond, &m_pthreadMutex); } if (shutdown) { pthread_mutex_unlock(&m_pthreadMutex); printf("thread %lu will exit\n", pthread_self()); pthread_exit(NULL); } printf("tid %lu run\n", tid); vector<CTask*>::iterator iter = m_vecTaskList.begin(); /** * 取出一个任务并处理之 */ CTask* task = *iter; if (iter != m_vecTaskList.end()) { task = *iter; m_vecTaskList.erase(iter); } pthread_mutex_unlock(&m_pthreadMutex); task->Run(); /** 执行任务 */ printf("tid:%lu idle\n", tid); } return (void*)0; } /** * 往任务队列里边添加任务并发出线程同步信号 */ int CThreadPool::AddTask(CTask *task) { pthread_mutex_lock(&m_pthreadMutex); this->m_vecTaskList.push_back(task); pthread_mutex_unlock(&m_pthreadMutex); pthread_cond_signal(&m_pthreadCond); return 0; } /** * 创建线程 */ int CThreadPool::Create() { pthread_id = (pthread_t*)malloc(sizeof(pthread_t) * m_iThreadNum); for(int i = 0; i < m_iThreadNum; i++) { pthread_create(&pthread_id[i], NULL, ThreadFunc, NULL); } return 0; } /** * 停止所有线程 */ int CThreadPool::StopAll() { /** 避免重复调用 */ if (shutdown) { return -1; } printf("Now I will end all threads!!\n"); /** 唤醒所有等待线程,线程池要销毁了 */ shutdown = true; pthread_cond_broadcast(&m_pthreadCond); /** 阻塞等待线程退出,否则就成僵尸了 */ for (int i = 0; i < m_iThreadNum; i++) { pthread_join(pthread_id[i], NULL); } free(pthread_id); pthread_id = NULL; /** 销毁条件变量和互斥体 */ pthread_mutex_destroy(&m_pthreadMutex); pthread_cond_destroy(&m_pthreadCond); return 0; } /** * 获取当前队列中任务数 */ int CThreadPool::getTaskSize() { return m_vecTaskList.size(); }
main.cpp
#include "Thread.h" #include <iostream> #include <unistd.h> #include <stdlib.h> class CMyTask: public CTask { public: CMyTask(){} inline int Run() { printf("%s\n", (char*)this->m_ptrData); sleep(10); return 0; } }; int main() { CMyTask taskObj; char szTmp[] = "this is the new thread running"; taskObj.SetData((void*)szTmp); CThreadPool threadPool(10); for(int i = 0; i < 20; i++) { threadPool.AddTask(&taskObj); } while(1) { printf("there are still %d tasks need to handle\n", threadPool.getTaskSize()); if (threadPool.getTaskSize() == 0) { if (threadPool.StopAll() == -1) { printf("Now I will exit from main\n"); exit(0); } } sleep(2); } return 0; }
- TCP_server
- TCP_server
- TCP_server
- TCP_Server
- tcp_server
- tcp_server
- TCP_server
- tcp_server
- 【网络】tcp_server
- 编写tcp_server
- tcp_server.c服务模型
- tcp_server的实现
- tcp_server和tcp_client
- tcp_server的实现
- socket网络编程之TCP_Server
- Linux套接字编程tcp_server
- 【Linux】中TCP_server的实现
- LINUX--TCP_server端的编写
- 操作集合的工具类Collections
- 非结构化数据是什么
- 【模块】二维三点定位算法
- adb命令
- Tomcat源码分析-JMX之Registry类(中)
- TCP_server
- angularJs-Tab切换
- 函数组合与集合管道模式 迭代 Java 中集合的函数模式
- [bzoj2150] 部落战争(二分图最小边覆盖)
- 18位身份证合法性验证 带年龄限制
- 8086实模式的内存布局
- HttpServlet容器响应Web客户请求
- Spring中BeanPostProcessor与InitializingBean接口的关系与应用
- caffe 学习笔记之ubuntu14.04安装