1. 程式人生 > >C指標原理(45)-LINUX應用

C指標原理(45)-LINUX應用

 一、在linux平臺下,每個執行緒可有專用資料:

#include <pthread.h>

#include <stdio.h>
struct mydata{
       int x;
       char c[4];
};
pthread_t pthreada,pthreadb;
pthread_key_t datakey;//每個程序建立一次,不同的執行緒,同樣名字的鍵指向不同的地方

void *cleanup_mydata(void *dataptr){//刪除鍵時呼叫的
    free((struct mydata*)dataptr);
}
void anum1(){
    int rc;
    struct  mydata *mdata=(struct mydata*)malloc(sizeof(struct mydata));
    mdata->x=1;
    mdata->c[0]='a';
    mdata->c[1]='\0'; 
    rc=pthread_setspecific(datakey,(void*)mdata);//設定鍵指向的值,注意這個mdata為值的記憶體,必須使用指標的方式指向記憶體 
    sleep(1);
    struct  mydata *mmdata=(struct mydata*)pthread_getspecific(datakey);//取出鍵指向的值,注意這個mdata為值的記憶體,必須使用指標的方式指向記憶體 
    printf("-%d-%s\n",mmdata->x,mmdata->c); 
    fflush(stdout); 
}
void bnum2(){
    int rc;
    struct  mydata *mdata=(struct mydata*)malloc(sizeof(struct mydata));
    mdata->x=2;
    mdata->c[0]='b';
    mdata->c[1]='\0'; 
    rc=pthread_setspecific(datakey,(void*)mdata);//設定鍵指向的值,注意這個mdata為值的記憶體,必須使用指標的方式指向記憶體 
    sleep(1);
    struct  mydata *mmdata=(struct mydata*)pthread_getspecific(datakey);//取出鍵指向的值,注意這個mdata為值的記憶體,必須使用指標的方式指向記憶體 
    printf("-%d-%s\n",mmdata->x,mmdata->c);
    fflush(stdout); 
}

int main(void){

    int rc;

    rc=pthread_key_create(&datakey,cleanup_mydata);//為鍵刪除時的清理函式
    pthread_create(&pthreada,NULL,anum1,NULL); 
    pthread_create(&pthreadb,NULL,bnum2,NULL);  
    sleep(3);
    pthread_join(pthreada,NULL);   
    pthread_join(pthreadb,NULL);  
    rc=pthread_key_delete(datakey); //僅刪除鍵,但不刪除值指向的記憶體,執行緒終止呼叫使用者自定義的刪除函式,本例中為cleanup_mydata

}

二、摸擬shell

通過execlp函式來實現 ,execlp函式用於執行檔案

其引數與說明為:

#include <process.h>

int execlp( const char file,
const char
arg0,
const char arg1,

const char
argn,
NULL );
file,
const char arg0,
const char
arg1,

const char * argn,
NULL );
Arguments:
file

Used to construct a pathname that identifies the new process image file. If the fileargument contains a slash character, the file argument is used as the pathname for the file. Otherwise, the path prefix for this file is obtained by a search of the directories passed as the environment variable PATH.

arg0, …, argn

Pointers to NULL-terminated character strings. These strings constitute the argument list available to the new process image. Terminate the list terminated with a NULL pointer. The arg0 argument must point to a filename that's associated with the process.

waitpid()
wait for process termination 

Function
 SYNOPSIS DESCRIPTION PARAMETERS RETURN VALUES CONFORMANCE MULTITHREAD SAFETY LEVEL PORTING ISSUES AVAILABILITY SEE ALSO 
SYNOPSIS
#include <sys/types.h>

#include <sys/wait.h>

pid_t waitpid(pid_t pid, int *stat_loc, int options);

DESCRIPTION
The waitpid() function lets the calling process obtain status information about one of its child processes. If status information is available for two or more child processes, the order in which their status is reported is unspecified. If more than one thread is suspended in waitpid() awaiting termination of the same process, exactly one thread returns the process status at the time of the target child process termination. The other threads return -1, with errno set to ECHILD.

If the calling process sets SIGCHLD to SIG_IGN, and the process has no unwaited for children that were transformed into zombie processes, the calling thread blocks until all of the children of the process terminate, at which time waitpid() returns -1 with errno set to ECHILD.

If the parent process terminates without waiting for all of its child processes to terminate, the remaining child processes are assigned a new parent process ID corresponding to a system-level process.

PARAMETERS

pid 

Specifies a set of child processes for which the status is requested:

If pid is equal to -1, status is requested for any child process. In this respect, waitpid() is equivalent to wait().
If pid is greater than 0, it specifies the process ID of a single child process for which status is requested.
If pid is 0, status is requested for any child process whose process group ID is equal to that of the calling process. This setting is not currently supported.
If pid is less than -1, status is requested for any child process whose process group ID is equal to the absolute value of pid. This setting is not currently supported.

stat_loc 

Specifies the location to which the child process' exit status is stored. If NULL is passed, no exit status is returned. Otherwise, the following macros defined in <sys/wait.h> can be used to evaluate the returned status:

WIFEXITED(s) 

Evaluates to a non-zero value if status was returned for a child process that exited normally.

WEXITSTATUS(s) 

If the value of WIFEXITED(s) is non-zero, this macro evaluates to the low-order 8 bits of the status argument that the child process passed to exit() or _exit(), or to the value that the child process returned from main().

WIFSIGNALED(s) 

Evaluates to a non-zero value if status was returned for a child process that terminated due to receipt of a signal that was not caught.

WTERMSIG(s) 

If the value of WIFSIGNALED(s) is non-zero, this macro evaluates to the number of the signal that caused the termination of the child process.

WIFCORED(s) 

Evaluates to a non-zero value if status was returned for a child process that terminated due to receipt of a signal that was not caught, and whose default action is to dump core.

WCOREDUMP(s) 

Evaluates to a non-zero value if status was returned for a child process that terminated due to receipt of a signal that was not caught, and whose default action is to dump core.

WCORESIG(s) 

If the value of WIFCORED(s) is non-zero, this macro evaluates to the number of the signal that caused the termination of the child process.

WIFSTOPPED(s) 

Evaluates to a non-zero value if status was returned for a child process that is currently stopped.

WSTOPSIG(s) 

If the value of WIFSTOPPED(s) is non-zero, this macro evaluates to the number of the signal that caused the child process to stop.

options 

Is the bitwise inclusive-OR of zero or more of the following flags, defined in <sys/wait.h>:

WNOHANG 

The waitpid() function does not suspend execution of the calling thread if status is not immediately available for one of the child processes specified by pid.

WUNTRACED 

The status of any child processes specified by pid that are stopped, and whose status has not yet been reported since they stopped, is also reported to the requesting thread. This value is currently not supported, and is ignored.

RETURN VALUES
If waitpid() was invoked with WNOHANG set in options, and there are children specified by pid for which status is not available, waitpid() returns 0. If WNOHANG was not set,waitpid() returns the process ID of a child when the status of that child is available. Otherwise, it returns -1 and sets errno to one of the following values:

ECHILD 

The process or process group specified by pid does not exist or is not a child of the calling process.

EFAULT 

stat_loc is not a writable address.

EINTR 

The function was interrupted by a signal. The value of the location pointed to by stat_loc is undefined.

EINVAL 

The options argument is not valid.

ENOSYS 

pid specifies a process group (0 or less than -1), which is not currently supported.

程式如下:

#include <stdio.h>
#include <sys/wait.h>

#define MAXLINE 100
//execlp模擬SHELL

int main(void){
   int pid;
   int jg,status,len;
   char buf[MAXLINE];

   printf("\n##myhaspl~~");//自定義的shell提示符
   while(fgets(buf,MAXLINE,stdin)!=NULL){//讀入一行
        len=strlen(buf)-1;
        if (buf[len]=='\n'){        //去除換行符,execlp只接受以NULL結尾
            buf[len]=0;            
        }
        pid=fork();
        if (pid<0){
           printf("fork error!\n");
        }
        else if (pid==0){//子程序
           printf("\n");        
           if (buf[0]=='Q'&&strlen(buf)==1){//鍵入Q表示退出shell          
               exit(200); 
           }
           jg=execlp(buf,buf,(char *)0);
           if (jg==-1){//錯誤
              printf("不能執行:%s\n",buf);    
              exit(127);          
           }              
              exit(0);       
        }
        if ((jg==waitpid(pid,&status,0))<0){//父程序
            printf("waitpid error\n");
        }
        if (WEXITSTATUS(status)==200) {//WEXITSTATUS計算返回值
                printf("退出....\n");  
                break;          
        }
        printf("\n##myhaspl~~");//自定義的shell提示符
   }
exit(0);
}

執行:
[email protected]:~/private/mytest$ gcc -o test21 test21.c
test21.c: In function ‘main’:
test21.c:15: warning: incompatible implicit declaration of built-in function ‘strlen’
test21.c:26: warning: incompatible implicit declaration of built-in function ‘exit’
test21.c:28: warning: incompatible implicit declaration of built-in function ‘execlp’
test21.c:31: warning: incompatible implicit declaration of built-in function ‘exit’
test21.c:33: warning: incompatible implicit declaration of built-in function ‘exit’
test21.c:44: warning: incompatible implicit declaration of built-in function ‘exit’
[email protected]:~/private/mytest$ ./test21

##myhaspl~~ls

1     pvmtest   test20   testbswap  testmul.s    x
ex.txt     test      test20.c    testbswap.s  testmutex    x.c
gmon.out     test12.s  test21   test.c  testmutex.c  xx
hello     test13    test21.c    test.c~  testpopen    xx.c
hello.c      test13.c  test2.c   testmes  testpopen.c  xx.txt
hello.o      test15    test6   testmes.c  testpvm1.c   xxx.txt
hello.s      test15.c  test66   testmesrecv  testpvm2.c   xxxx.txt
main     test19    test66.s    testmesrecv.c  testpx       xy
main.c     test19.c  test6.c   testmessnd  testpx1
main.c~      test1.c   testasmc    testmessnd.c   testpx1.s
myhello.txt  test2     testasmc.c  testmul  testpx.s

##myhaspl~~xx

不能執行:xx

##myhaspl~~Q

退出....

[email protected]:/mnt-system/lx/test$ gcc -D_REENTRANT -lpthread -o testcondout testcondout.c
[email protected]:/mnt-system/lx/test$ ./testcondout

please input an integer:(<=1000)26
time out
time out
1/1 finished,push 1.0000000000
1/2 finished,push 0.5000000000
1/3 finished,push 0.3333333333
1/4 finished,push 0.2500000000
1/5 finished,push 0.2000000000
time out
1/6 finished,push 0.1666666667
1/7 finished,push 0.1428571429
1/8 finished,push 0.1250000000
1/9 finished,push 0.1111111111
1/10 finished,push 0.1000000000
time out
1/11 finished,push 0.0909090909
1/12 finished,push 0.0833333333
1/13 finished,push 0.0769230769
1/14 finished,push 0.0714285714
1/15 finished,push 0.0666666667
1/1:1.0000000000 added result 1.0000000000
1/2:0.5000000000 added result 1.5000000000
1/3:0.3333333333 added result 1.8333333333
1/4:0.2500000000 added result 2.0833333333
1/5:0.2000000000 added result 2.2833333333
1/6:0.1666666667 added result 2.4500000000
1/7:0.1428571429 added result 2.5928571429
1/8:0.1250000000 added result 2.7178571429
1/9:0.1111111111 added result 2.8289682540
1/10:0.1000000000 added result 2.9289682540
1/11:0.0909090909 added result 3.0198773449
1/12:0.0833333333 added result 3.1032106782
1/13:0.0769230769 added result 3.1801337551
1/14:0.0714285714 added result 3.2515623266
1/15:0.0666666667 added result 3.3182289932
1/1:1.0000000000 computed result 1.0000000000
1/2:0.5000000000 computed result 0.5000000000
1/3:0.3333333333 computed result 0.8333333333
1/4:0.2500000000 computed result 0.5833333333
1/5:0.2000000000 computed result 0.7833333333
1/6:0.1666666667 computed result 0.6166666667
1/7:0.1428571429 computed result 0.7595238095
1/8:0.1250000000 computed result 0.6345238095
1/9:0.1111111111 computed result 0.7456349206
1/10:0.1000000000 computed result 0.6456349206
1/11:0.0909090909 computed result 0.7365440115
1/12:0.0833333333 computed result 0.6532106782
1/13:0.0769230769 computed result 0.7301337551
1/14:0.0714285714 computed result 0.6587051837
1/15:0.0666666667 computed result 0.7253718504
===============compute finish!=========== result:0.7253718504
1/16 finished,push 0.0625000000
1/17 finished,push 0.0588235294
1/18 finished,push 0.0555555556
1/19 finished,push 0.0526315789
1/20 finished,push 0.0500000000
1/16:0.0625000000 added result 3.3807289932
1/17:0.0588235294 added result 3.4395525226
1/18:0.0555555556 added result 3.4951080782
1/19:0.0526315789 added result 3.5477396571
1/20:0.0500000000 added result 3.5977396571
1/21 finished,push 0.0476190476
1/22 finished,push 0.0454545455
1/23 finished,push 0.0434782609
1/24 finished,push 0.0416666667
1/25 finished,push 0.0400000000
time out
1/16:0.0625000000 computed result 0.6628718504
1/17:0.0588235294 computed result 0.7216953798
1/18:0.0555555556 computed result 0.6661398242
1/19:0.0526315789 computed result 0.7187714032
1/20:0.0500000000 computed result 0.6687714032
1/21:0.0476190476 computed result 0.7163904508
1/22:0.0454545455 computed result 0.6709359053
1/23:0.0434782609 computed result 0.7144141662
1/24:0.0416666667 computed result 0.6727474995
1/25:0.0400000000 computed result 0.7127474995
===============compute finish!=========== result:0.7127474995
1/21:0.0476190476 added result 3.6453587048
1/22:0.0454545455 added result 3.6908132502
1/23:0.0434782609 added result 3.7342915111
1/24:0.0416666667 added result 3.7759581778
1/25:0.0400000000 added result 3.8159581778
1/26 finished,push 0.0384615385
time out
time out
1/26:0.0384615385 computed result 0.6742859611
===============compute finish!=========== result:0.6742859611
1/26:0.0384615385 added result 3.8544197162
================add finish!============ result:3.8544197162

2個執行緒完成累加和累加減運算(其中一個採用超時等待條件訊號,另一個採用等待條件訊號),n個執行緒完成計算每個符點數

  ```
 #include <pthread.h>  
   #include <bits/pthreadtypes.h>  
   #include <stdio.h>  
   #include <stdlib.h>  
   #include <errno.h> 
   #define MAXS 1000   
   #define MAXTDS 5 //執行緒池大小
    
     
  double myjg[MAXS+1];//計算結果存放位置  
  int max;  
  pthread_mutex_t eventlock;   //互斥鎖
  pthread_cond_t myevent;   //條件變數
  pthread_t threads[MAXTDS+2];   //執行緒池,完成1/n計算
  int isend=0;

  int done;    
    
 void mycomp(void x){//計算1/i的結果,計算結果放在一個數組中。  
   int i=0;
   int rc;
   while (1){ 
  pthread_mutex_lock(&eventlock);  
  if (isend){
             pthread_mutex_unlock(&eventlock); 
             break;            
  }  
  i=myjg[0];//myjg[0]存放著執行緒已經計算到的i。   
  if (i<max){
      i++;
      myjg[0]=i;     
  }  
         if (i==max){//最後一個數
             myjg[i]=(1/(double)i);
              isend=1;
           printf("1/%d finished,push %.10f\n",i,myjg[i]); 
              fflush(stdout);
              pthread_mutex_unlock(&eventlock); 
              sleep(3);
              rc=pthread_cond_signal(&myevent);//廣播訊號,多個任務不被阻塞,多個任務競爭互斥鎖的所有權。也可以使用pthread_cond_signal(&event);傳送訊號,這樣只有一個執行緒不被阻塞,其它執行緒都被阻塞。
              if (rc){
                  perror("pthread_cond_broadcast");
                  fflush(stdout);
              }  
              sleep(2);  
              break;     
         }
    
     //開始計算
     myjg[i]=(1/(double)i);  
     printf("1/%d finished,push %.10f\n",i,myjg[i]); 
     fflush(stdout);
     pthread_mutex_unlock(&eventlock);   
     if (!(i%MAXTDS)){
        sleep(3); 
        pthread_cond_broadcast(&myevent);//廣播訊號,多個任務不被阻塞,多個任務競爭互斥鎖的所有權。也可以使用pthread_cond_signal(&event);傳送訊號,這樣只有一個執行緒不被阻塞,其它執行緒都被阻塞。    
        sleep(3); 
     }
  } 
  pthread_exit(NULL);
}  

    
 void myprint1(void xx){//讀取陣列,將計算結果累加,最終完成1/1+1/2+1/3+......+1/n的計算,使用超時等待  
   int maxi;  
   int curj=1;  
   double jg=0; 
   int rc; 
   struct timeval now;//使用微秒
   struct timespec timeout;  //使用納秒

      
   while(curj<=max)  
     {  
      //取當前時間
      // myhaspl 
         gettimeofday(&now);
      //準備時間間隔
        timeout.tv_sec=now.tv_sec+1;
        timeout.tv_nsec=now.tv_usec*1000;
         maxi=0;
        
         pthread_mutex_lock(&eventlock);//用於條件變數的互斥,條件變數就是一個用來發送事件發生訊號的訊號量
         rc=pthread_cond_timedwait(&myevent,&eventlock,&timeout);//在等待條件變數myevent的發生,超時就返回,不再等待。條件變數必須與一個互斥鎖eventlock相關聯,條件變數不提供鎖定,必須有一個互斥鎖eventlock配合。
        //互斥鎖eventlock在呼叫wait前應鎖定,然後在wait期間,互斥量eventlock被解鎖。掛起執行緒執行,直到條件變數myevent收到訊號             

         if (rc==0){  // myhaspl
              maxi=myjg[0]; 
              fflush(stdout); 
              pthread_mutex_unlock(&eventlock);
              for (;curj<=maxi;curj++)
              {    // myhaspl
                   jg+=myjg[curj];  
                   printf("1/%d:%.10f added result %.10f\n",curj,myjg[curj],jg);     
                   fflush(stdout);                
              }   

         } 
         else if (rc==ETIMEDOUT){//TIMEOUT
              printf("time out\n");
              fflush(stdout); 
              pthread_mutex_unlock(&eventlock); 
              continue;            
         } 
         else  {  // myhaspl
              perror("pthread_cond_wait");
              fflush(stdout); 
              pthread_mutex_unlock(&eventlock); 
              continue;              
         }
    }  
    printf("================add finish!============ result:%.10f\n",jg);//輸出累加結果。  
    fflush(stdout);
    pthread_exit(NULL);
}  
    
void myprint2(void xx){//讀取陣列,將計算結果完成1/1+1/2-1/3+1/4-1/5......的計算  
   int maxi=0;  
   int curi=1;  
   double jg=0; 
   int fh=1;
   int rc; 
   while(curi<=max)  
     {  
         maxi=0;
         sleep(2); 
         pthread_mutex_lock(&eventlock);//用於條件變數的互斥,條件變數就是一個用來發送事件發生訊號的訊號量
         rc=pthread_cond_wait(&myevent,&eventlock);//在等待條件變數myevent的發生。條件變數必須與一個互斥鎖eventlock相關聯,條件變數不提供鎖定,必須有一個互斥鎖eventlock配合。
        //互斥鎖eventlock在呼叫wait前應鎖定,然後在wait期間,互斥量eventlock被解鎖。掛起執行緒執行,直到條件變數myevent收到訊號  
  // myhaspl
         if (rc==0){
              maxi=myjg[0]; 
              fflush(stdout); 
              pthread_mutex_unlock(&eventlock);
              while (curi<=maxi){              
                    jg+=fh*myjg[curi];  
                    printf("***1/%d:%.10f computed result %.10f\n",curi,myjg[curi],jg);  
                    fflush(stdout);       
                    fh=-fh;
                    curi++;
             }                 
             printf("===============compute finish!=========== result:%.10f\n",jg);//輸出累加結果 
             fflush(stdout);              
         } 
         else{//error
              perror("pthread_cond_wait");
              fflush(stdout); 
              pthread_mutex_unlock(&eventlock); 
              continue;            
         }  
   }      

    pthread_exit(NULL);
 }  
   
   int main(){  
   //計算1+1/2+1/3+......和1+1/2-1/3+1/4-1/5......  

     pthread_mutex_init(&eventlock,NULL);
     pthread_cond_init(&myevent,NULL);         
     int i =0;
     
     printf("please input an integer:(<=%d)",MAXS);  
     while (scanf("%d",&max),max>MAXS){//n的最大值  
        printf("please input an integer:(<=%d)",MAXS);  
     };  
     //myhaspl
     myjg[0]=0;
  
     pthread_create(&(threads[i]),NULL,myprint1,(void )&i);
     sleep(1); 
     i++;      
     pthread_create(&(threads[i]),NULL,myprint2,(void
)&i);  
     sleep(1);  
     i++; 
     for (;i<=MAXTDS;i++){  
         pthread_create(&(threads[i]),NULL,mycomp,(void )&i);  
         sleep(1);        
    }   
    sleep(MAXTDS
2*(i/10+1));  //wait......
    pthread_mutex_destroy(&eventlock);    
    return(0);  
 }   
     


一、埠

1、0-1023:預留埠,超級使用者使用

2、1024-49151:已經註冊的埠號

3、49152-65535:可自由使用的埠或動態埠

二、套接字型別

1、SOCK_STREAM(位元組流套接字):面向連線,可靠的全雙工位元組流。對於AF_INET來說,建立TCP連線

2、SOCK_DGRAM(資料報套接字):不保證資料正確分發,不保證傳送資料的訓序。對於AF_INET來說,建立UDP連線

3、SOCK_RAW(原始套接字)

三、建立套接字

int fd;

fd=socket(AF_INET,SOCK_STREAM,0);//除使用SOCK_RAW外,最後一個protocol被設定為0,AF_INET為套介面

 四、應用 

1.server

[email protected]:~/private/mytest$ ./testtcps
server wait....
............................
server read :myhaspl
 
server send :hello
.....
server read :myhaspl
 
server send :hello
2.client
[email protected]:~/private/mytest$ ./testtcpc
client send....
client send :myhaspl

client read :hello

[email protected]:~/private/mytest$ ./testtcpc
client send....
client send :myhaspl

client read :hello

[email protected]:~/private/mytest$ 

3.source
1)server
C程式碼  

#include <stdio.h>  
#include <errno.h>  
#include <sys/types.h>  
#include <sys/socket.h>  
#include <netinet/in.h>  
//myhaspl  
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) {//資料讀取前,操作被訊號中斷  
             perror("中斷錯誤");  
             readcn=0;             
          }  
          else {return -1;}//無法修復錯誤,返回讀取失敗  
       }  
       else if(readcn==0) break;//EOF  
         
         
       noreadcn-=readcn;//讀取成功,但是如果讀取的字元數小於maxc,則繼續讀,因為可能資料還會繼續通過網路送過來      
       buf+=readcn;    
       if (buf==0) break;//如果讀到字串結尾標誌則退出,必須有這句,否則會死迴圈  
       }    
  
  
       
    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){  
    int fd;  
    int addresslen;  
    struct sockaddr_in address;//地址資訊結構  
    int pid;  
    int rc;  
    fd_set fdset;  
      
  
  
                    
    //建立socket  
    fd=socket(AF_INET,SOCK_STREAM,0);//fd為socket  
    if (fd==-1){//錯誤,型別從errno獲得  
        perror("error");//perror先輸出引數,後跟":"加空格,然後是errno值對應的錯誤資訊(不是錯誤程式碼),最後是一個換行符。          
    }  
      
    //bind 到socket fd      
    address.sin_family=AF_INET;//IPV4協議,AF_INET6是IPV6  
    address.sin_addr.s_addr=htonl(INADDR_ANY);//l表示32位,htonl能保證在不同CPU的相同位元組序  
    address.sin_port=htons(1253);//埠號,s表示16位  
    addresslen=sizeof(address);  
      
  
    bind(fd,(struct sockaddr
)&address,addresslen);//bind  
      
           //建立socket佇列,指定最大可接受連線數  
           rc=listen(fd,32);//最多接收32個連線,開始監聽  
           //int listen(int sockfd, int backlog)返回:0──成功, -1──失敗  
           //核心會在自己的程序空間裡維護一個佇列以跟蹤這些完成的連線但伺服器程序還沒有接手處理或正在進行的連線  
           if (rc==-1) {  
              perror("listen error");//監聽失敗  
              exit(1);  
           }  
           printf("server wait....\n");             
           while(1){  
  
              struct sockaddr_in clientaddress;  
              int address_len;  
              int client_sockfd;  
              char mybuf[100];      
              char buf="hello\n";    
              struct timeval timeout;//超時結構體  
              //超時為2秒  
              timeout.tv_sec=1;  
              timeout.tv_usec=0;  
              //設定fdset  
              FD_ZERO(&fdset);//清除fdset  
              FD_CLR(fd,&fdset);//清除fd的標誌  
              FD_SET(fd,&fdset);//設定標誌  
              //select  
              if ((select(fd+1,&fdset,NULL,NULL,&timeout))<0){  
                  perror("select error");  
                  fflush(stdout);                
              }  
              //等待連線,使用新的程序或執行緒來處理連線  
  
              fflush(stdout);       
              address_len=sizeof(clientaddress);                
              if(FD_ISSET(fd,&fdset)){  
                  //如果有連線到來  
                 client_sockfd=accept(fd,(struct sockaddr
)&clientaddress,&address_len);//client_sockfd可理解為一個檔案控制代碼,能用read和write操作。client_address是客戶端資訊結構 myhaspl  
                
              //fork程序來處理每個客戶的連線        
                  pid=fork();  
               if (pid<0){//錯誤  
                    printf("error:%s\n",strerror(errno));//strerror將errno對映為一個錯誤資訊串 myhaspl  
                    close(client_sockfd);  
                    exit(1);   
                }     
  
                 if (pid==0){ //子程序處理每個客戶端的資料              
                     close(fd);//子程序關閉不需要它處理的監聽資源  
  
                      //讀取資料 myhaspl  
                      bzero(mybuf,100);                     
                     readn(client_sockfd,(void )mybuf,100);  
                      printf("\nserver read :%s",mybuf);                    
                     //傳送資料                    
                      writen(client_sockfd,(void
)buf,strlen(buf)+1);                 
                       printf("\nserver send :%s",buf);                  
                       close(client_sockfd);  
                       exit(0);  
                 }  
                  else {//父程序  
                          close(client_sockfd);//父程序不處理客戶端連線,因此關閉,但並不意味著把子程序的處理控制代碼關閉,因為子程序繼承了父程序的client_sockfd資源         myhaspl       
                 }                                 
            }else{  
                  printf(".");  
                  fflush(stdout);  
            }  
       }  
 }  

 2) client
C程式碼  

#include <stdio.h>  
#include <errno.h>  
#include <sys/types.h>  
#include <sys/socket.h>  
#include <netinet/in.h>  
//myhaspl  
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) {//資料讀取前,操作被訊號中斷 myhaspl  
             perror("中斷錯誤");  
             readcn=0;              
          }  
          else {return -1;}//無法修復錯誤,返回讀取失敗  
       }  
       else if(readcn==0) break;//EOF myhaspl  
             
       noreadcn-=readcn;//讀取成功,但是如果讀取的字元數小於maxc,則繼續讀,因為可能資料還會繼續通過網路送過來      
       buf+=readcn;     
        if (buf==0) break;    //如果讀到字串結尾標誌則退出,必須有這句,否則會死迴圈  myhaspl  
       }     
  
    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){  
    int fd;  
    int addresslen;  
    struct sockaddr_in address;//地址資訊結構 myhaspl  
    int pid;  
    char mybuf[100];          
    char
buf="myhaspl\n";  
    int rc;  
  
  
    fd=socket(AF_INET,SOCK_STREAM,0);//建立socket  
    if (fd==-1){//錯誤,型別從errno獲得  
        perror("error");//perror先輸出引數,後跟":"加空格,然後是errno值對應的錯誤資訊(不是錯誤程式碼),最後是一個換行符。    myhaspl       
    }  
    
    printf("client send....\n");  
    fflush(stdout);  
      
    //連線  
    address.sin_family=AF_INET;//IPV4協議,AF_INET6是IPV6 myhaspl  
    address.sin_addr.s_addr=inet_addr("127.0.0.1");//l表示32位,htonl能保證在不同CPU的相同位元組序  
    address.sin_port=htons(1253);//埠號,s表示16位 myhaspl  
    addresslen=sizeof(address);          
    rc=connect(fd,(struct sockaddr )&address,addresslen);//連線伺服器 myhaspl  
    if (rc==-1){//rc=0成功,rc=-1失敗 myhaspl  
      perror("連線錯誤");  
      exit(1);  
    }  
    //傳送資料   
    writen(fd,(void
)buf,strlen(buf)+1);  
    printf("client send :%s\n",buf);        
    //讀取資料  
    bzero(mybuf,100);    
    readn(fd,(void *)mybuf,100);   
    printf("client read :%s\n",mybuf);   
    close(fd);  
    exit(0);                  
  
 }  


執行緒池共享記憶體+訊號量
[email protected]:~/private/mytest$ gcc -std=gnu99 -o testshm testshm.c
testshm.c: In function ‘main’:
testshm.c:38: warning: implicit declaration of function ‘semget’
testshm.c:41: warning: implicit declaration of function ‘exit’
testshm.c:41: warning: incompatible implicit declaration of built-in function ‘exit’
testshm.c:45: warning: implicit declaration of function ‘semctl’
testshm.c:48: warning: incompatible implicit declaration of built-in function ‘exit’
testshm.c:51: warning: implicit declaration of function ‘shmget’
testshm.c:54: warning: incompatible implicit declaration of built-in function ‘exit’
testshm.c:57: warning: implicit declaration of function ‘shmat’
testshm.c:60: warning: incompatible implicit declaration of built-in function ‘exit’
testshm.c:63: warning: implicit declaration of function ‘memset’
testshm.c:63: warning: incompatible implicit declaration of built-in function ‘memset’
testshm.c:69: warning: incompatible implicit declaration of built-in function ‘exit’
testshm.c:78: warning: implicit declaration of function ‘strlen’
testshm.c:78: warning: incompatible implicit declaration of built-in function ‘strlen’
testshm.c:85: warning: implicit declaration of function ‘memcpy’
testshm.c:85: warning: incompatible implicit declaration of built-in function ‘memcpy’
testshm.c:92: warning: implicit declaration of function ‘semop’
testshm.c:95: warning: incompatible implicit declaration of built-in function ‘exit’
testshm.c:119: warning: incompatible implicit declaration of built-in function ‘strlen’
testshm.c:124: warning: incompatible implicit declaration of built-in function ‘exit’
testshm.c:132: warning: implicit declaration of function ‘wait’
testshm.c:134: warning: implicit declaration of function ‘shmdt’
testshm.c:139: warning: implicit declaration of function ‘shmctl’
testshm.c:142: warning: incompatible implicit declaration of built-in function ‘exit’
[email protected]:~/private/mytest$ ./testshm
 
deepfuture.javeye.com#line 1$deepfuture
 
deepfuture.javeye.com#line 2$javaeye
 
deepfuture.javeye.com#line 3$com
 
deepfuture.javeye.com#line 4$myhaspl
 
deepfuture.javeye.com#line 5$Q
 
deepfuture.javeye.com#line 6$
退出....
[email protected]:~/private/mytest$ cat abc.txt
deepfuture
javaeye
com
myhaspl
[email protected]:~/private/mytest$ 

C程式碼  

#include <stdio.h>  
#include <unistd.h>  
#include <linux/types.h>  
#include <linux/shm.h>  
#include <linux/sem.h>  
#include <linux/ipc.h>  
  
  
  
  
#define MAXS  (1024+1)  
#define BUFFERSIZE  200  
#define SEMID 251//訊號標誌  
#define FILENAME "abc.txt"  
#define SHMKEY 241//共享記憶體標誌  
#define SHMSIZE MAXS//共享記憶體大小  
  
  
//程式完成父程序接收鍵盤輸入,子程序存入檔案FILENAME。  
//myhaspl  
  
int main(void){  
    char strbuf[MAXS];  
    char buf[BUFFERSIZE];  
    int sem_id;  
    int shm_id;  
    int pid;  
    int rc,res;  
    struct sembuf sem_op;//訊號集結構  
    union semun sem_val;//訊號量數值  
    char cur;  
    FILE
myfile;  
    char shm_addr;  
    int line=1;  
  
      
    //建立訊號量集,其中只有一個訊號量 myhaspl   
    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共享記憶體。連線共享記憶體 myhaspl   
    shm_addr=(char
)shmat(shm_id,NULL,0);//返回共享記憶體地址 myhaspl   
    if (!shm_addr){  
        printf("shmat error!\n");  
        exit(1);      
    }   
    //初始化資料  
    memset(shm_addr,'\0',MAXS);    
    cur=shm_addr;//當前字元起始地址  
    //建立程序  
    pid=fork();  
    if (pid==-1){  
        printf("fork error!\n");  
        exit(1);             
    }  
    else if(pid==0){//子程序,接受鍵盤輸入,往共享記憶體中寫字元行 myhaspl   
         int isend=0;//是否結束輸入  
         printf("\ndeepfuture.javeye.com#line %d$",line); //自定義鍵盤輸入時使用的SHELL外觀     
         while((!isend)&&fgets(buf,BUFFERSIZE,stdin)!=NULL){//從shell中讀入一行    
             line++;         
             printf("\ndeepfuture.javeye.com#line %d$",line); //自定義鍵盤輸入時使用的SHELL外觀     
                 
             if (buf[0]=='Q'&&strlen(buf)<=2){//單個字元Q表示退出輸入  
                 isend++;//退出輸入  
                 printf("\n退出....\n");  
             }  
             else  
             {//如果不是退出命令                         
               //寫共享記憶體 myhaspl                      
               memcpy(cur,buf,strlen(buf));              
               cur+=strlen(buf);  
             }    
               //寫入一行,增加訊號  
               sem_op.sem_num=0;  
               sem_op.sem_op=1;  
               sem_op.sem_flg=0;  
               semop(sem_id,&sem_op,1);//操作訊號量,每次+1          
          }   
          cur=-1;   
          exit(0);     
    }  
    else{//父程序,從共享記憶體中讀字元行 ,並寫入檔案    myhaspl          
            
          while(1)  
          {  
            //讀出一行,減少訊號  myhaspl   
              sem_op.sem_num=0;  
              sem_op.sem_op=-1;  
              sem_op.sem_flg=0;  
              semop(sem_id,&sem_op,1);//操作訊號量,每次-1     
              
              //myhaspl  讀共享記憶體中一行  
             if ((
cur)==-1) break;//輸入結束  
             int i;  
                  for (i=0;cur!='\n';cur++,i++){                 
                        buf[i]=
cur;              
                  }     
              cur++;                    
              buf[i]='\n';  
              buf[++i]=0;  
            
              //寫檔案  
              FILE fp=fopen(FILENAME,"ab");  
              res=fwrite(buf,strlen(buf),1,fp);//myhaspl  寫入一個行,長度為strlen(buf),個數為1            
              //size_t fwrite(const void
ptr,size_t size,size_t nmemb,FILE * stream);  
              //size為要寫入的每個資料的大小(多少位元組),nmemb為要寫入資料的個數。myhaspl   
              if (res==-1){     
                  perror("write error on pipe\n");     
                  exit(1);                     
              }   
              fclose(fp);    
                          
          }  
  
                        
        
          wait(&pid);//等待子程序結束,即使用者輸入完畢  
          //分離共享程序  
          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);   
         }  
}  

 fgets(由檔案中讀取一字串) 
相關函式 open,fread,fscanf,getc 
表頭檔案 include<stdio.h> 
定義函式 har * fgets(char * s,int size,FILE * stream); 
函式說明 fgets()用來從引數stream所指的檔案內讀入字元並存到引數s所指的記憶體空間,直到出現換行字元、讀到檔案尾或是已讀了size-1個字元為止,最後會加上NULL作為字串結束。 
返回值 gets()若成功則返回s指標,返回NULL則表示有錯誤發生。 
範例 #include<stdio.h>
main()
{
char s[150];
fputs(fgets(s,150,stdin),stdout);
}

執行 ,輸入:

Hello world

輸出:

Hello world

fputs(將一指定的字串寫入檔案內) 
相關函式 fopen,fwrite,fscanf,fputc,putc 
表頭檔案 #include<stdio.h> 
定義函式 int fputs(const char * s,FILE * stream); 
函式說明 fputs()用來將引數s所指的字串寫入到引數stream所指的檔案內。 
返回值 若成功則返回寫出的字元個數,返回EOF則表示有錯誤發生。 

fgets()儲存輸入中的換行符,而fputs()也不為輸出新增換行符。

strtok()用來將字串分割成一個個片段。引數str指向欲分割的字串,引數delimiters則為分割字串,當strtok()在引數str的字串中發現到引數delimiters的分割字元時則會將該字元改為'\0'字元。在第一次呼叫時,strtok()必需給予引數str字串,往後的呼叫則將引數str設定成NULL。

C/C++中的Split函式是strtok()其函式原型如下: 
char * strtok (char * str, const char * delimiters); 
函式說明 
strtok()用來將字串分割成一個個片段。引數str指向欲分割的字串,引數delimiters則為分割字串,當strtok()在引數str的字串中發現到引數delimiters的分割字元時則會將該字元改為'\0'字元。在第一次呼叫時,strtok()必需給予引數str字串,往後的呼叫則將引數str設定成NULL。每次呼叫成功則返回下一個分割後的字串指標。 
返回值 返回下一個分割後的字串指標,如果已無從分割則返回NULL。

下面到底哪個是陣列指標,哪個是指標陣列呢:
A)
lo