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 (pid0){//子進程
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 ((jgwaitpid(pid,&status,0))<0){//父進程
printf(“waitpid error\n”);
}
if (WEXITSTATUS(status)==200) {//WEXITSTATUS計算返回值
printf(“退出…\n”);
break;
}
printf("\n##myhaspl~~");//自定義的shell提示符
}
exit(0);
}
執行:
deepfuture@deepfuture-laptop:~/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’
deepfuture@deepfuture-laptop:~/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
退出…
knoppix@Microknoppix:/mnt-system/lx/test$ gcc -D_REENTRANT -lpthread -o testcondout testcondout.c
knoppix@Microknoppix:/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){ // myhasplmaxi=myjg[0]; fflush(stdout); pthread_mutex_unlock(&eventlock);for (;curj<=maxi;curj++){ // myhaspljg+=myjg[curj]; printf("1/%d:%.10f added result %.10f\n",curj,myjg[curj],jg); fflush(stdout); } } else if (rc==ETIMEDOUT){//TIMEOUTprintf("time out\n");fflush(stdout); pthread_mutex_unlock(&eventlock); continue; } else { // myhasplperror("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收到信號 // myhasplif (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{//errorperror("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); }; //myhasplmyjg[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(MAXTDS2*(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.serverdeepfuture@deepfuture-laptop:~/private/mytest$ ./testtcps server wait.... ............................ server read :myhasplserver send :hello ..... server read :myhasplserver send :hello 2.client deepfuture@deepfuture-laptop:~/private/mytest$ ./testtcpc client send.... client send :myhasplclient read :hellodeepfuture@deepfuture-laptop:~/private/mytest$ ./testtcpc client send.... client send :myhasplclient read :hellodeepfuture@deepfuture-laptop:~/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); } 線程池共享內存+信號量 deepfuture@deepfuture-laptop:~/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’ deepfuture@deepfuture-laptop:~/private/mytest$ ./testshmdeepfuture.javeye.com#line 1$deepfuturedeepfuture.javeye.com#line 2$javaeyedeepfuture.javeye.com#line 3$comdeepfuture.javeye.com#line 4$myhaspldeepfuture.javeye.com#line 5$Qdeepfuture.javeye.com#line 6$ 退出.... deepfuture@deepfuture-laptop:~/private/mytest$ cat abc.txt deepfuture javaeye com myhaspl deepfuture@deepfuture-laptop:~/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 worldfputs(將一指定的字符串寫入文件內) 相關函數 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) long *pa[6]; B) long (*pb)[6]; 每次上課問這個問題,總有弄不清楚的。這里需要明白一個符號之間的優先級問題。“[]”的優先級比“*”要高。pa 先與“[]”結合,構成一個數組的定義,數組名為pa,long *修飾的是數組的內容,即數組的每個元素。那現在我們清楚,這是一個數組,其包含10 個指向long 類型數據的指針,即指針數組。至于pb ,“()”的優先級比“[]”高,“*”號和pb 構成一個指針的定義,指針變量名為pb,long 修飾的是數組的內容,即數組的每個元素。數組在這里并沒有名字,是個匿名數組。pb 是一個指針,它指向一個包含10 個int 類型數據的數組,即數組指針。下面程序完成一個簡單的單機投票系統:1. 1.dat與2.dat存放了2個投票的相關內容,投票內容可以依次增多,按數字增序排列。1.dat:4您最喜歡的語言javascriptpythonC++java22.dat:4您最喜歡的操作系統windowsubuntufreebsdSolaris12.投票程序每次運行后都會讀取上次投票的結果,并保存本次投票結果,結果保存為csv文件。3.候選人及相關數據保存在下面2個結構中tphsr.h: #ifndef TPHSR_H_INCLUDED#define TPHSR_H_INCLUDED\//候選人結構struct tp_hsr{int id;char name[10];//候選人int sel_count;//候選人選票};typedef struct tp_hsr TpHsr;struct tp_hsr_info{TpHsr *tphsr;//候選人明細int hsrcount;//候選人總數char outfn[200];//候選人導出文件名char xzinfo[200];//選舉內容int sel_max;//最大候選人};typedef struct tp_hsr_info TpHsrInfo;#endif // TPHSR_H_INCLUDED其它代碼如下:tp.h: #ifndef TP_H_INCLUDED#define TP_H_INCLUDED#include <string.h>#include <conio.h>#include "tphsr.h"#define PASSWD_LEN 100//密碼最大長度#define HSR_MAXLEN 100//候選人模板每行長度#define TMPL_FL_PATH "template/"#define FDCOUNT 2void showbegin(){system("cls");printf(" * *** * \n");printf(" * **** * \n");printf(" * **** **\n");printf(" * * ***** * \n");printf(" ***** * * ** ** * \n");printf(" **** *\n");printf(" * ** *** * * **\n");printf(" * *** ** *** \n");printf(" * ***** * \n");printf(" * *** * \n");printf(" * \n");printf(" * * * ***** \n");printf(" \n投 好 莊 嚴 一 票\n ");printf(" # ####### # ##### # \n");printf(" # # # # # # # # # # # ##### \n");printf(" # # # # # # # # # # # # \n");printf(" # # ######### # # # # # # # # # \n");printf(" # # # # # # # ### \n");printf(" # # # # # # ####### # # # # \n");printf(" # # # # # # # # # # # \n");printf(" #### # # # #### # # #### # ####### \n");}TpHsrInfo read_hsr_template(char templ_fn){//讀取候選人模板文件FILE *hsrfp;int hsrcount=0;char strline[HSR_MAXLEN];char myfilename[200]="";char outfn[200]="";char *xz_info;strcat(myfilename,TMPL_FL_PATH);strcat(myfilename,templ_fn);if((hsrfp = fopen(myfilename,"rt")) == NULL){return NULL;}//取得候選人總數//第一行為候選人總數fgets(strline,HSR_MAXLEN,hsrfp);hsrcount=atoi(strline);//取得選舉內容//第二行為選舉內容fgets(strline,HSR_MAXLEN,hsrfp);xz_info=strline;TpHsrInfo myhsrinfo=(TpHsrInfo)malloc(sizeof(TpHsrInfo));TpHsr myhsr=malloc(sizeof(TpHsr)hsrcount);myhsrinfo->tphsr=myhsr;myhsrinfo->hsrcount=hsrcount;strncpy(myhsrinfo->xzinfo,xz_info,strlen(xz_info)-1);myhsrinfo->xzinfo[strlen(xz_info)-1]='\0';strcat(outfn,myhsrinfo->xzinfo);strcat(outfn,".csv");strcpy(myhsrinfo->outfn,outfn);int i=0;while (!feof(hsrfp)){fgets(strline,HSR_MAXLEN,hsrfp); //讀取一行strline[strlen(strline)-1]='\0';myhsrinfo->tphsr[i].id=i+1;strcpy(myhsrinfo->tphsr[i].name,strline);myhsrinfo->tphsr[i].sel_count=0;i++;if (i>=hsrcount) break;}fgets(strline,HSR_MAXLEN,hsrfp);myhsrinfo->sel_max=atoi(strline);fclose(hsrfp);return myhsrinfo;}TpHsrInfo load_hsr(char templ_fn ){//讀文件FILE *hsrin_fp;int hsrcount=0;int i=0;const char *csvflag=",";char * p;char strline[HSR_MAXLEN+10];int sel_ct=0;char* sel_ctstr[5];TpHsrInfo *tphsrinfo=read_hsr_template(templ_fn);if(tphsrinfo==NULL){return NULL;}if((hsrin_fp = fopen(tphsrinfo->outfn,"rt")) == NULL){return tphsrinfo;}while (!feof(hsrin_fp)){fgets(strline,HSR_MAXLEN+10,hsrin_fp);p = strtok (strline,csvflag);p = strtok(NULL,csvflag);if (!p) break;strcpy(sel_ctstr,p);sel_ct=atoi(sel_ctstr);tphsrinfo->tphsr[i].sel_count=sel_ct;i++;}fclose(hsrin_fp);return tphsrinfo;}void save_hsr(TpHsrInfo *tphsrinfo){//寫文件FILE *hsrout_fp;int hsrcount=0;char linestr[300]={0};int i=0;char sel_ctstr[5]="";if((hsrout_fp = fopen(tphsrinfo->outfn,"wt")) == NULL){printf("%s創建錯誤!",tphsrinfo->outfn);return NULL;}for(i=0; i<tphsrinfo->hsrcount;i++){strcpy(linestr,tphsrinfo->tphsr[i].name);strcat(linestr," ,");sprintf(sel_ctstr,"%d",tphsrinfo->tphsr[i].sel_count);strcat(linestr,sel_ctstr);strcat(linestr,"\n");fputs(linestr,hsrout_fp);}fclose(hsrout_fp);}int select_hsr(TpHsrInfo *tphsrinfo){//顯示候選人int i=0;int xz=0;int hsrsel_max=tphsrinfo->sel_max;int now_selhsr_ct=1;system("cls");printf("-------%s-------\n",tphsrinfo->xzinfo);for(i=0; i<tphsrinfo->hsrcount;i++){printf("%d-",tphsrinfo->tphsr[i].id);printf(tphsrinfo->tphsr[i].name);printf(" 票數:%d",tphsrinfo->tphsr[i].sel_count);printf("\t");if ((i+1)%FDCOUNT==0) printf("\n");}printf("請輸入編號(輸入0表示棄權):");scanf("%d",&xz);while (1){if (xz<0 || xz>tphsrinfo->hsrcount){printf("-------%s-------\n",tphsrinfo->xzinfo);for(i=0; i<tphsrinfo->hsrcount;i++){printf("%d-",tphsrinfo->tphsr[i].id);printf(tphsrinfo->tphsr[i].name);printf(" 票數:%d",tphsrinfo->tphsr[i].sel_count);printf("\t");if ((i+1)%FDCOUNT==0) printf("\n");}i=0;printf("請輸入編號:");scanf("%d",&xz);}else if (xz==0) {printf("您棄權了!");return 0;}else {printf("您選擇:%d-%s",tphsrinfo->tphsr[xz-1].id,tphsrinfo->tphsr[xz-1].name);tphsrinfo->tphsr[xz-1].sel_count++;now_selhsr_ct++;if (now_selhsr_ct<=hsrsel_max) {xz=-1;continue;}return 1;}}}void showtip(){printf("\n每位候選人均有一個編碼,輸入選中的編碼后,按回車鍵即表示投票!\n按任意鍵開始投票\n");getch();}int passwd_check(){//密碼檢測,成功返回1,否則返回0showbegin();int i;char mypass[100];char accept[]="gxds"; //正確登錄密碼printf("投票選舉系統\n");printf("請輸入密碼:");char pswd;for(i=0; i<PASSWD_LEN-1; i++){pswd=getch();if (pswd==0x0d) break;else mypass[i]=pswd;printf("*");}mypass[i]='\0';if (strcmp(mypass,accept)==0){printf("\n密碼正確!下面開始投票!\n");return 1;}else{printf("\n密碼錯誤!按任意鍵退出程序!\n");getch();return 0;}}#endif // TP_H_INCLUDEDMain.c//投票軟件-單機版//純C,請使用code::blocks打開工程,并編譯#include <stdio.h>#include "tp.h"#define TPL_MAX 20int main(int argc,char *argv[]){int is_pass=passwd_check();TpHsrInfo *tphsrinfo[TPL_MAX];int now_jx=0;char nowjxfn[20]="";int max_jx=0;while(1){if (is_pass) {sprintf (nowjxfn,"%d",now_jx+1);strcat(nowjxfn,".dat");tphsrinfo[now_jx]=load_hsr(nowjxfn);if (tphsrinfo[now_jx]==NULL) {max_jx=now_jx;break;}showbegin();showtip();select_hsr(tphsrinfo[now_jx]);now_jx++;}else return 0;}now_jx=0;for (now_jx=0;now_jx<max_jx;now_jx++){save_hsr(tphsrinfo[now_jx]);free(tphsrinfo[now_jx]->tphsr);free(tphsrinfo[now_jx]);}return 0;}總結
以上是生活随笔為你收集整理的C指针原理(45)-LINUX应用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: null、undefined、NaN区分
- 下一篇: linux bash 历史记录,Linu