`
deepfuture
  • 浏览: 4398632 次
  • 性别: Icon_minigender_1
  • 来自: 湛江
博客专栏
073ec2a9-85b7-3ebf-a3bb-c6361e6c6f64
SQLite源码剖析
浏览量:80057
1591c4b8-62f1-3d3e-9551-25c77465da96
WIN32汇编语言学习应用...
浏览量:70012
F5390db6-59dd-338f-ba18-4e93943ff06a
神奇的perl
浏览量:103313
Dac44363-8a80-3836-99aa-f7b7780fa6e2
lucene等搜索引擎解析...
浏览量:285668
Ec49a563-4109-3c69-9c83-8f6d068ba113
深入lucene3.5源码...
浏览量:15002
9b99bfc2-19c2-3346-9100-7f8879c731ce
VB.NET并行与分布式编...
浏览量:67517
B1db2af3-06b3-35bb-ac08-59ff2d1324b4
silverlight 5...
浏览量:32120
4a56b548-ab3d-35af-a984-e0781d142c23
算法下午茶系列
浏览量:45970
社区版块
存档分类
最新评论

文本SOCKET客户端,多进程可解决网速较慢问题,有命令缓冲功能

阅读更多

/*

starclient.c

程序: 刘兴(deepfuturelx@gmail.com)[deepfuture.iteye.com],

最后修改时间:2010.10.25

功能:文本客户端,多进程可解决网速较慢问题,有命令缓冲功能

*/

 

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <errno.h> 

#include <linux/types.h>

#include <linux/shm.h>

#include <linux/sem.h>

#include <linux/ipc.h>

#include <sys/socket.h>

#include <netinet/in.h>

 

 

 

 

#define MAXS  500//命令缓冲区的大小(以字节为单位),这里测试用所以得比较小,最好设置为1024+1,请尽可能大点,因为太小可能导致后来的命令把前面没有执行的命令覆盖

#define BUFFERSIZE  40//接收键盘输入缓冲区

#define SEMID 251//信号标志

#define FILENAME "abc.txt"

#define SHMKEY 241//共享内存标志

#define SHMSIZE MAXS//共享内存大小

#define CMDMAX 20//命令的最长

 

 

//程序完成父进程接收键盘输入,子进程向服务器遄输出。

ssize_t readn(int fd,void *ptr,size_t maxcn){//读取n个字符,maxc为读取的数目

    size_t noreadcn,readcn;

    char *buf=ptr;

 

 

    noreadcn=maxcn;

    while(noreadcn>0){

       if ( (readcn=read(fd,buf,noreadcn))<0){//读数据

 

          if (errno==EINTR) {//数据读取前,操作被信号中断 deepfuture.iteye.com

             perror("中断错误");

             readcn=0;            

          }

          else {return -1;}//无法修复错误,返回读取失败

       }

       else if(readcn==0) break;//EOF deepfuture.iteye.com

 

       noreadcn-=readcn;//读取成功,但是如果读取的字符数小于maxc,则继续读,因为可能数据还会继续通过网络送过来    

       buf+=readcn;   

        if (*buf==0) break;    //如果读到字符串结尾标志则退出,必须有这句,否则会死循环  deepfuture.iteye.com

       }   

 

    return (maxcn-noreadcn);

}

 

ssize_t writen(int fd,void *ptr,size_t maxcn){//写入n个字符

    size_t nowritecn,writecn;

    char *buf=ptr;

 

    nowritecn=maxcn;

    while(nowritecn>0){

       if((writecn=write(fd,buf,nowritecn))<=0){//写数据

          if (errno==EINTR) {//数据写前,操作被信号中断

             perror("中断错误");

             writecn=0;             

          }

          else {return -1;}//无法修复错误,返回读取失败

       }

 

       nowritecn-=writecn;

       buf+=writecn; 

 

       }  

       return (maxcn-nowritecn);

}

 

 

int main(void){

    char strbuf[MAXS];

    char buf[BUFFERSIZE];

    int sem_id;

    int shm_id;

    int pid;

    int rc,res;

    int fd;

    int addresslen;

    struct sembuf sem_op;//信号集结构

    union semun sem_val;//信号量数值

    struct sockaddr_in address;//地址信息结构 deepfuture.iteye.com

    char *inputcur;

    char *outputcur;

    FILE *myfile;

    char *shm_addr;

    char mybuf[100]; 

 

 

 

 

    //建立信号量集,其中只有一个信号量 

    sem_id=semget(SEMID,1,IPC_CREAT|0600);//SEMID为为正整数,则为公共的;1为信号集的数量;

    if (sem_id==-1){

        printf("create sem error!\n");

        exit(1);    

    }

    //信号量初始化

    sem_val.val=0;

    rc=semctl(sem_id,0,SETVAL,sem_val);//设置信号量

    if (rc==-1){

        printf("initlize sem error!\n");

        exit(1);    

    }

    //建立共享内存

    shm_id=shmget(SHMKEY,SHMSIZE,IPC_CREAT|0600);//参数为:标志,大小,权限

    if (shm_id==-1){

        printf("create shm error!\n");

        exit(1);    

    }     

    //attach共享内存。连接共享内存 deepfuture.iteye.com 

    shm_addr=(char *)shmat(shm_id,NULL,0);//返回共享内存地址 

    if (!shm_addr){

        printf("shmat error!\n");

        exit(1);    

    } 

    //初始化数据

    memset(shm_addr,'\0',MAXS);  

    inputcur=shm_addr;//输入当前字符起始地址

    outputcur=shm_addr;//输出当前字符起始地址

    //创建进程

    pid=fork();

    if (pid==-1){

        printf("fork error!\n");

        exit(1);           

    }

    else if(pid==0){//子进程,接受键盘输入,往共享内存中写字符行

         int isend=0;//是否结束输入

  printf("\n#welcome to StarSea mud game (http://starsea.bigbbs.cn/)\n"); //自定义键盘输入时使用的SHELL外观   

  printf("\n#StarSea$"); //自定义键盘输入时使用的SHELL外观 

         while((!isend)&&fgets(buf,BUFFERSIZE,stdin)!=NULL){//从shell中读入一行  

         

             if (buf[0]=='Q'&&strlen(buf)<=2){//单个字符Q表示退出输入

                 isend++;//退出输入

                 printf("\n退出StarSea....\n");

                 *inputcur=-1; 

             }

             else if (buf[0]=='\n'&strlen(buf)<2){ //空命令

                 printf("\n请输入命令\n");

    printf("\n#StarSea$"); //自定义键盘输入时使用的SHELL外观 

                 continue;

             }

             else if (strlen(buf)>(CMDMAX-2)){

                       printf("\n命令长度不能超过%d\n",CMDMAX-2);

          printf("\n#StarSea$"); //自定义键盘输入时使用的SHELL外观 

                       continue;

             }

             else

             {//如果不是退出命令 

         printf("\n#StarSea$"); //自定义键盘输入时使用的SHELL外观

                  fflush(stdout); 

                    if ((MAXS-(inputcur-shm_addr))<=CMDMAX){//缓冲区不够,清空,cur指针复位

 

                      inputcur=shm_addr;//当前字符起始地址    

 

                   }

         //写共享内存           

           memcpy(inputcur,buf,strlen(buf));     

         inputcur+=strlen(buf);

 

         }  

         //写入一行,增加信号

               sem_op.sem_num=0;

               sem_op.sem_op=1;

               sem_op.sem_flg=0;

               semop(sem_id,&sem_op,1);//操作信号量,每次+1 

 

       *inputcur=-1; 

     exit(0);   

    }

    else{//父进程,从共享内存中读字符行 ,并写入文件 

 

          address.sin_family=AF_INET;//IPV4协议,AF_INET6是IPV6 deepfuture.iteye.com

          address.sin_addr.s_addr=inet_addr("127.0.0.1");//l表示32位,htonl能保证在不同CPU的相同字节序

          address.sin_port=htons(1253);//端口号,s表示16位 deepfuture.iteye.com

         addresslen=sizeof(address);      

          while(1)

          {

             int rc;

 

            //读出一行,减少信号

              sem_op.sem_num=0;

              sem_op.sem_op=-1;

              sem_op.sem_flg=0;

              semop(sem_id,&sem_op,1);//操作信号量,每次-1   

 

          // 读共享内存中一行

         if ((*outputcur)==-1) {//输入结束

                     break;

                 }

                      int i;

              for (i=0;*outputcur!='\n';outputcur++,i++){              

                    buf[i]=*outputcur;          

              }   

          outputcur++;              

            buf[i]='\n';

          buf[++i]=0;

 

                  if ((MAXS-(outputcur-shm_addr))<=CMDMAX){//缓冲区不够,清空,cur指针复位

                      outputcur=shm_addr;//当前字符起始地址   

                  }

                  while(1){  //连接

             fd=socket(AF_INET,SOCK_STREAM,0);//建立socket

                      if (fd==-1){//错误,类型从errno获得

                          perror("error");//perror先输出参数,后跟":"加空格,然后是errno值对应的错误信息(不是错误代码),最后是一个换行符。    

                       }

                 rc=connect(fd,(struct sockaddr *)&address,addresslen);//连接服务器 deepfuture.iteye.com

           if (rc==-1){//rc=0成功,rc=-1失败 

                             close(fd);

               perror("服务器断开,20秒后重新连接....(ctrl+c退出)");

                      printf("\n#StarSea$"); //自定义键盘输入时使用的SHELL外观

                             fflush(stdout); 

                             sleep(20);

                         } 

                         else{//成功

                             break;

                         }    

                  }

                  //发送数据 

                  writen(fd,(void *)buf,strlen(buf)+1);

                  bzero(mybuf,100);  

                  readn(fd,(void *)mybuf,100); 

                  printf("\n#%s",mybuf); 

         printf("\n#StarSea$"); //自定义键盘输入时使用的SHELL外观

                  fflush(stdout); 

 

 

                  close(fd);

 

                      

          }

 

                  

    

     wait(&pid);//等待子进程结束,即用户输入完毕

                  memset(shm_addr,'\0',MAXS); 

     //分离共享进程

     if (shmdt(shm_addr)==-1){

              printf("shmdt error!\n");        

     }

     //撤销共享内存,任何进程只要有权限,都可以撤销共享内存,不一定非要创建它的进程

     struct shmid_ds shm_desc;

     if (shmctl(shm_id,IPC_RMID,&shm_desc)==-1){

         printf("shmctl error!\n");

     }

     exit(0); 

    }

}

 

 

0
0
分享到:
评论

相关推荐

    socket客户端,可连接多个服务器

    总的来说,这个"socket客户端,可连接多个服务器"的实现涉及了Socket编程的基础,TCP连接的建立与恢复,以及客户端的错误处理和重连策略。理解这些知识点对于开发分布式系统、网络应用或者其他需要网络通信的项目都...

    socket客户端_socket_

    标题“socket客户端_socket_”表明我们将探讨的是如何创建和使用Socket客户端,而描述中的“之前已经上传服务端demo”提示我们已经有了Socket服务端的基础。 在Socket编程中,客户端是发起连接请求的一方,它需要...

    socket客户端

    Socket客户端是网络编程中的一个重要概念,它允许程序通过TCP或UDP协议与其他运行在网络上的程序进行通信。在本案例中,我们关注的是一个使用C#语言编写的Socket客户端代码,这通常用于实现客户端-服务器(C/S)架构...

    Socket客户端.zip

    Socket客户端在IT行业中是网络编程的一个重要组成部分,主要用于实现不同计算机之间的通信。Socket,也称为套接字,是操作系统提供的一种进程间通信机制,尤其在网络环境中,它为应用程序提供了发送和接收数据的能力...

    C#SOCKET 客户端与主机通讯多线程实现

    在C#编程中,Socket是用于网络通信的基本组件,它提供了进程间通信(IPC)的能力,使得客户端和服务器能够相互通信。在这个“C# SOCKET 客户端与主机通讯多线程实现”主题中,我们将深入探讨如何利用C#的Socket类...

    socket 客户端和代码

    本示例中,我们关注的是一个基于C++和MFC(Microsoft Foundation Classes)实现的Socket客户端,该客户端已经过验证,可以与服务端进行有效通信。以下是关于这个主题的详细知识点: 1. **Socket基本概念**: - ...

    VC编制Socket客户端

    在IT行业中,网络编程是不可或缺的一部分,而Socket编程则是实现网络通信的基础。本文将深入探讨如何使用Microsoft Visual C++(简称VC)来编制一个Socket客户端。Socket,也被称为套接字,是网络上的两个进程间通信...

    SuperSocket写Socket客户端(连接,重连,接收处理数据)

    SuperSocket写Socket客户端(连接,重连,接收处理数据)

    C# Socket 客户端服务端封装带使用实例

    4. 多连接处理:由于一个Socket只能处理一个连接,如果要同时处理多个客户端,可以使用线程或者异步编程模型来并发处理。 5. 服务端关闭:关闭监听Socket,释放资源。 五、队列处理 在高并发场景下,使用队列处理...

    socket 客户端

    Socket客户端是计算机网络编程中的一个重要概念,主要用于实现应用程序间的通信。在本文中,我们将深入探讨Socket客户端的工作原理、如何向服务端发送数据以及接收服务端响应消息的过程。 首先,Socket是一种网络...

    vc++ 多线程socket客户端

    在VC++中,我们通常使用Winsock库来实现Socket功能,这个库提供了Windows平台下的Socket API。 ### 二、多线程技术 多线程是操作系统并发执行多个线程的能力。在Socket客户端应用中,多线程可以用于同时处理多个...

    java编写的SOCKET客户端

    这个软件可以任意设置目标IP和端口实现连接相应的主机服务器,编写语言为java,安装时候需要有相应的java环境运行。

    SuperSocket客户端+服务端完整demo

    `SuperSocket` 是一个轻量级、高度可扩展的C#开发的网络通信框架,它简化了基于TCP协议的客户端和服务器应用程序的开发。这个完整Demo提供了从头开始构建一个简单的客户端和服务端应用程序的基础,特别适合初学者...

    C#利用Socket实现客户端之间直接通信

    C#利用Socket实现客户端之间直接通信 实验功能:  设计程序,分别构建通信的两端:服务器端和客户端应用程序,套接字类型为面向连接的Socket,自己构建双方的应答模式,实现双方的数据的发送和接收(S发给C,C发给S)...

    Socket客户端

    Socket客户端是网络编程中一种常见的工具,主要用于在开发过程中进行通信调试。Socket,又称为套接字,是网络层面上应用程序之间进行数据交换的一种接口。它允许程序通过Internet或局域网进行通信,实现了进程间的...

    Linux下Socket 多进程多客户端通信

    在Linux操作系统中,Socket编程...总之,Linux下的Socket多进程多客户端通信涉及到了进程创建、并发处理、同步机制、Socket通信以及进程间通信等多个方面。理解并掌握这些知识点,对于构建高效稳定的网络服务至关重要。

    C#SuperSocket---客户端源程序

    3. **命令**: 命令是SuperSocket处理客户端请求的方式,每个命令通常对应一个特定的操作或业务逻辑。 4. **事件驱动**: 超级套接字基于.NET的事件模型,例如`NewConnect`事件会在新的客户端连接建立时触发,`Receive...

    服务器和客户端进程的简单SOCKET通讯

    本主题将深入探讨“服务器和客户端进程的简单SOCKET通讯”,帮助理解整个连接过程。 1. **Socket基础概念** - **Socket**:Socket在操作系统层面是一个数据接口,用于两个网络应用程序之间进行双向通信。它可以...

    C# Socket 客户端服务端封装 支持多连接处理 Tasks多线程 队列处理 大数据拆分包处理

    在IT领域,网络通信是应用程序之间进行数据交换的关键技术,而C#中的Socket编程则提供了实现这一功能的基础。本文将详细解析标题和描述中提到的"C# Socket客户端服务端封装,支持多连接处理,Tasks多线程,队列处理...

    服务器客户端-socket(进程线程)

    服务器客户端-socket(进程线程),包括套接字,多线程,多进程,单进程,并发,互斥锁,tcp/ip,udp等

Global site tag (gtag.js) - Google Analytics