客户端、服务器端编程

首先是从main函数开发:

int main(itn argc,char* argv[])

{

pthread_t thread;

int count;

int status;

client_threads = CLIENT_THREADS;

for(count = 0;count <client_threads,count++)

{

status = pthread_create(&thread,NULL,client_routine,(void*)count);

if(status != 0)

err_abort(status,"Create client thread");

}

status = pthread_mutex_lock(&client_mutex);

if(status != 0)

err_abort(status,"Lock client mutex");

while(client_threads>0)

{

status = pthread_cond_wait(&clients_done,&client_mutex);

if(status != 0)

err_abort(status,"Wait for client to finish");

}

status = pthread_mutex_unlock(&client_mutex);

if(status != 0)

err_abort(status,"Unlock client mutex");

printf("All client done\n");

tty_server_request(REQ_QUIT,1,NULL,NULL);

return 0;

}

这个main函数在中间for循环中,调用pthread_create函数创建4个线程,传递给线程的数据位count(0,1,2,3).调用client_routine函数。

void *client_routine(void *arg)

{

int my_number = (int)arg,loops;

char prompt[32];

char string[128],formatted[128];

int status;

sprintf(prompt,"Client 5d>",my_number);

while(1)

{

tty_server_request(REQ_READ,1,prompt,string);

if(strlen(string) ==0)

break;

for(loops =0;loops <4;loops++)

{

sprintf(formatted,"(%d#%d)%s",my_number,loops,string);

tty_server_request(REQ_WRITE,0,NULL,formatted);

sleep(1);

}

}

status = pthread_mutex_lock(&client_mutex);

if(status != 0)

err_abort(status,"Lock client mutex");

client_threads--;

if(client_threads <= 0)

{

status = pthread_cond_signal(&clients_done);

if(status != 0)

err_abort(status,"Signale client done");

}

status = pthread_mutex_unlock(7client_mutex);

if(status != 0)

err_abort(status,"Unlock client mutex");

return NULL;

}

pthread_cond_wait() 用于阻塞当前线程,等待别的线程使用pthread_cond_signal()或pthread_cond_broadcast来唤醒它。 pthread_cond_wait() 必须与pthread_mutex
配套使用。pthread_cond_wait()函数一进入wait状态就会自动release mutex。当其他线程通过pthread_cond_signal()或pthread_cond_broadcast,把该线程唤醒,使pthread_cond_wait()通过(返回)时,该线程又自动获得该mutex。

pthread_cond_signal函数的作用是发送一个信号给另外一个正在处于阻塞等待状态的线程,使其脱离阻塞状态,继续执行.如果没有线程处在阻塞等待状态,pthread_cond_signal也会成功返回。

使用pthread_cond_signal一般不会有“惊群现象”产生,他最多只给一个线程发信号。假如有多个线程正在阻塞等待着这个条件变量的话,那么是根据各等待线程优先级的高低确定哪个线程接收到信号开始继续执行。如果各线程优先级相同,则根据等待时间的长短来确定哪个线程获得信号。但无论如何一个pthread_cond_signal调用最多发信一次。

但是pthread_cond_signal在多处理器上可能同时唤醒多个线程,当你只能让一个线程处理某个任务时,其它被唤醒的线程就需要继续 wait,而且规范要求pthread_cond_signal至少唤醒一个pthread_cond_wait上的线程,其实有些实现为了简单在单处理器上也会唤醒多个线程.

另外,某些应用,如线程池,pthread_cond_broadcast唤醒全部线程,但我们通常只需要一部分线程去做执行任务,所以其它的线程需要继续wait.所以强烈推荐对pthread_cond_wait() 使用while循环来做条件判断.

在这里如果没有线程,则通知等待创建线程唤醒wait在此条件变量上的等待。

上面全部代码:

#include <pthread.h>

#include <math.h>

#include "errors.h"

#define CLIENT_THREADS 4

#define REQ_READ 1

#define REQ_WRITE 2

#define REQ_QUIT 3

typedef struct request_tag

{

struct request_tag *next;

int operation;

int synchronous;

int done_flag;

pthread_cond_t done;

char prompt[32];

char text[128];

}request_t;

typedef struct tty_server_tag

{

request_t *first;

request_t *last;

int running;

pthread_mutex_t mutex;

pthread_cond_t request;

}tty_server_t;

tty_server_t tty_server =

{

NULL,NULL,0,PTHREAD_MUTEX_INITIALIZER,PTHREAD_COND_INITIALIZER

};

int client_threads;

pthread_mutex_t client_mutex = PTHREAD_MUTEX_INITIALIZER;

pthread_cond_t clients_done = PTHREAD_COND_INITIALIZER;

void *tty_server_routine(void *arg)

{

static pthread_mutex_t prompt_mutex = PTHREAD_MUTEX_INITIALIZER;

request_t *request;

int operation,len;

int status;

while(1)

{

status = pthread_mutex_lock(&tty_server.mutex);

if(status != 0)

err_abort(status,"Lock server mutex");

while(tty_server.first ==NULL)

{

status = pthread_cond_wait(&tty_server.request,&tty_server.mutex);

if(status != 0)

{

err_abort(status,"Wait for request");

}

request = tty_server.first;

tty_server.first= request->next;

if(tty_server.first == NULL)

{

tty_server.last = NULL;

}

status = pthread_mutex_unlock(&tty_server.mutex);

if(status != 0)

err_abrort(status,"Unlock server mutex");

operation = request->operation;

switch(operation)

{

case REQ_QUIT:

break;

case REQ_READ:

if(strlen(request->prompt)>0)

printf(request->prompt);

if(fgets(request->text,128,stdin)==NULL)

request->text[0]=‘\0‘;

len = strlen(request->text);

if(len>0&&request->text[len-1]==‘\n‘)

request->text[len-1]=‘\0‘;

break;

case REQ_WRITE:

puts(request->text);

break;

default:

break;

}

if(request->synchronous)

{

status = pthread_mutex_lock(&tty_server.mutex);

if(status != 0)

err_abort(status,"Lock server mutex");

request->done_flag =1;

status = pthread_cond__signal(&request->done);

if(status != 0)

err_abort(status,"Unlock server mutex");

}else

free(request);

if(operation ==REQ_QUIT)

break;

}

return NULL;

}

void tty_server_request(int operation,int sync,const char* prompt,char* string)

{

request_t *request;

int status;

status =pthread_mutex_lock(&tty_server.mutex);

if(status != 0)

err_abort(status,"Lock server mutex");

if(!tty_server.running)

{

pthread_t thread;

pthread_attr_t detached_attr;

status = pthread_attr_init(&detached_attr);

if(status != 0)

err_abort(status,"Init attributes object");

status = pthread_attr_setdetachstate(&detached_attr,PTHREAD_CREATE_DETACHED);

if(status != 0)

err_abort(status,"Set detach state");

tty_server.running = 1;

status = pthread_create(&thread,&detached_attr,tty_server_routine,NULL);

if(status != 0)

err_abort(status,"Create server");

pthread_attr_destroy(&detached_attr);

}

request = (request_t*)malloc(sizeof(request_t));

if(request ==NULL)

errno_abort("Allocate Request");

request->next = NULL;

request->operation = operation;

request->synchronous = sync;

if(sync)

{

request->done_flag = 0;

status = pthread_cond_init(&request->done,NULL);

if(status != 0)

err_abort(status ,"Init request condition");

}

if(prompt != NULL)

strncpy(request->prompt,prompt,32);

else

request->prompt[0]=‘\0‘;

if(operation == REQ_WRITE &&string != NULL)

strncpy(request->text,string,128);

else

request->text[0]=‘\0‘;

if(tty_server.first == NULL)

{

tty_server.first = request;

tty_server.last = request;

}else

{

(tty_server.last)->next = request;

tty_server.last= request;

}

status = pthread_cond_signal(&tty_server.request);

if(status != 0)

err_abort(status,"Wake server");

if(sync)

{

while(!request->done_flag)

{

status = pthread_cond_wait(&request->done,&tty_server.mutex);

if(status != 0)

err_abort(status,"Wait for sync request");

}

if(operation == REQ_READ)

{

if(strlen(request->text)>0)

strcpy(string,request->text);

else

string[0]=‘\0‘;

}

status = pthread_cond_destroy(&request->done);

if(status != 0)

err_abort(status,"destroy request condition");

free(request);

}

status = pthread_mutex_unlock(&tty-server.mutex);

if(status != 0)

err_abort(status,"Unlock mutex");

}

时间: 2024-10-31 14:13:55

客户端、服务器端编程的相关文章

客户端网页编程知识总结

一.企业应用计算的演变 演变周期是十年 1.主机/亚终端的集中计算模式 a.二十世纪七十年代,企业的应用程序是以围绕一个大型主机建立的. b.大型主机的特点是:庞大.昂贵.专用.(一个屏幕,一个键盘,一根主机连线,常用于超市收银.航空售票.小型储蓄所等),简称Mainframe/terminal c.集中计算模式的劣势:难于维护.一台计算机进行全部的处理.专用性是他们难于集成其他平台上的应用程序. 2.客户机/服务器计算模式(Client/Server) a.二十世界八十年代,随着个人pc机开始

【Qt5开发及实例】30、实现客户端的编程,UDP协议

udpclient.h /** * 书本:[Qt5开发及实例] * 功能:实现客户端的编程 * 文件:udpclient.h * 时间:2015年2月5日22:10:30 * 作者:cutter_point */ #ifndef UDPCLIENT_H #define UDPCLIENT_H #include <QDialog> #include <QVBoxLayout> #include <QTextEdit> #include <QPushButton>

GCM(谷歌云推送)客户端服务器端开发全指南(服务器篇)

今天我们按照之前所说的步骤介绍GCM云推送服务端的开发,因为服务端的开发比客户端的开发较简单,遵从由易到难,一步一步攻破的原则,所以我先于客户端讲服务端的开发,话不多说,让我们开始吧! 首先我们依旧来到首页 这次我们点击指南,进入到GCM开发Overview,这里概括了GCM客户端服务器端开发流程. 根据以下的流程图我们不难看出服务端和GCM的通信方式有两种 1.Http协议 2.Xmpp协议 Xmpp协议常用于双向通信,我们这里暂时不需要,因此果断选择Http协议来开发. 英语比较好的朋友可以

服务器端编程心得(三)—— 一个服务器程序的架构介绍

本文将介绍我曾经做过的一个项目的服务器架构和服务器编程的一些重要细节. 一.程序运行环境 操作系统:centos 7.0 编译器:gcc/g++ 4.8.3     cmake 2.8.11 mysql数据库:5.5.47 项目代码管理工具:VS2013 二.程序结构 该程序总共有17个线程,其中分为9个数据库工作线程D和一个日志线程L,6个普通工作线程W,一个主线程M.(以下会用这些字母来代指这些线程) (一).数据库工作线程的用途 9个数据库工作线程在线程启动之初,与mysql建立连接,也就

服务器端编程

我们的整个讨论都忽略了服务器端编程的问题.如果向服务器发出一个请求,会发生什么事情?大多数时候 的请求都是很简单的一个"把这个文件发给我".浏览器随后会按适当的形式解释这个文件:作为HTML 页. 一幅图.一个Java 程序片.一个脚本程序等等.向服务器发出的较复杂的请求通常涉及到对一个数据库进行 操作(事务处理).其中最常见的就是发出一个数据库检索命令,得到结果后,服务器会把它格式化成HTML 页,并作为结果传回来(当然,假如客户通过 Java 或者某种脚本语言具有了更高的智能,那么

linux-socket tcp客户端服务器编程模型及代码详解

上一篇文章介绍了 TCP/IP相关协议,socket通信流程和涉及到的各种函数: Socket简单理解 本篇将具体解释tcp客户端服务器编程模型相关的代码 文章分为4个部分: 1. TCP客户端服务器编程模型流程图 2. 网络字节序与主机字节序 3. TCP编程的地址结构 4. 详细案例代码及解释 一: TCP客户端服务器编程模型流程图 上面两张图片将整个流程已经说明的很清楚了; 二: 网络字节序与主机字节序 字节序即是保存数据的方向方式, 分为 大端存储 和 小端存储; 其中 网络字节序 使用

《Linux多线程服务器端编程》读书笔记第3章

<Linux多线程服务器端编程>第3章主要讲的是多线程服务器的适用场合与常用的编程模型. 1.进程和线程 一个进程是"内存中正在运行的程序“.每个进程都有自己独立的地址空间(address space).将"进程"比喻为"人",每个人都有自己的记忆(memory),人与人通过谈话(消息传递)来交流,谈话既可以是面谈(同一台服务器),也可以在电话里谈(不同的服务器,有网络通信).面谈和电话谈的区别在于,面谈可以立即知道对方是否死了(crash,S

客户端-服务器端互动比较与原生实例(比较ajax,server-sent event,websocket/netsocket)

昨日学习了websocket的原生实例,觉得有必要把几种常见的客户端-服务器端无刷新交互形式列举比较: 一.Ajax:客户端决定何时主动向Server端发请求 如:无刷新评论.无刷新更换图片. 主要目的是为了无刷新客户体验,但都是客户端的操作来触发向Server发送请求. 实例网上很多,原生的js或封装了的jQurey都算比较常用.易懂.易自助修改的方式. 二.Server-sent event:定时由Server端向客户端推送内容 如:每秒推送股市动态.每秒推送体育比赛文字转播. 特点是客户端

IOS Socket 04-利用框架CocoaAsyncSocket实现客户端/服务器端

这篇文章,我们介绍CocoaAsyncSocket框架的使用,主要介绍实现客户端/服务器端代码,相信在网上已经很多这样的文章了,这里做一下自己的总结.这里介绍使用GCD方式 一.客户端 1.下载地址 读者可以在github下载框架源码 https://github.com/robbiehanson/CocoaAsyncSocket 下载后,可以看到在Examples下面可以看到很多例子,如果读者自学能力高,可以略过下面的文章. 2.开始使用 1)在 \Source\GCD 目录下,我们可以看到G

服务器端编程示例

int fd_set_nonblock(int fd) { int rv; rv = fcntl(fd, F_GETFL, 0); if(rv < 0){ printf("fcntl error\n"); return -1; } rv = fcntl(fd, F_SETFL, rv | O_NONBLOCK); if(rv < 0){ printf("fcntl error\n"); return -1; } return 0; } int init_