建设银行招标网站wordpress改wp admin
七、_public.cpp
 #include "_public.h"
 // 如果信号量已存在,获取信号量;如果信号量不存在,则创建它并初始化为 value。
 // 如果用于互斥锁,value 填 1,sem_flg 填 SEM_UNDO。
 // 如果用于生产消费者模型,value 填 0,sem_flg 填 0。
 bool csemp::init(key_t key,unsigned short value,short sem_flg)
 {
 if (m_semid!=-1) return false; // 如果已经初始化了,不必再次初始化。
 m_sem_flg=sem_flg;
 // 信号量的初始化不能直接用 semget(key,1,0666|IPC_CREAT)
 // 因为信号量创建后,初始值是 0,如果用于互斥锁,需要把它的初始值设置为 1,
 // 而获取信号量则不需要设置初始值,所以,创建信号量和获取信号量的流程不同。
 // 信号量的初始化分三个步骤:
 // 1)获取信号量,如果成功,函数返回。
 // 2)如果失败,则创建信号量。
 // 3) 设置信号量的初始值。
 // 获取信号量。
 if ( (m_semid=semget(key,1,0666)) == -1)
 {
 // 如果信号量不存在,创建它。
 if (errno==ENOENT)
 {
 // 用 IPC_EXCL 标志确保只有一个进程创建并初始化信号量,其它进程只能获取。
 if ( (m_semid=semget(key,1,0666|IPC_CREAT|IPC_EXCL)) == -1)
 {
 if (errno==EEXIST) // 如果错误代码是信号量已存在,则再次获取信号量。
 {
 if ( (m_semid=semget(key,1,0666)) == -1)
 {
 perror("init 1 semget()"); return false;
 }
 return true;
 }
 else // 如果是其它错误,返回失败。
 {
 perror("init 2 semget()"); return false;
 }
 }
 // 信号量创建成功后,还需要把它初始化成 value。
 union semun sem_union;
 sem_union.val = value; // 设置信号量的初始值。
 if (semctl(m_semid,0,SETVAL,sem_union) < 0)
 {
 perror("init semctl()"); return false;
 }
 }
 else
 { perror("init 3 semget()"); return false; }
 }
 return true;
 }
 // 信号量的 P 操作(把信号量的值减 value),如果信号量的值是 0,将阻塞等待,直到信号量的值
 大于 0。
 bool csemp::wait(short value)
 {
 if (m_semid==-1) return false;
 struct sembuf sem_b;
 sem_b.sem_num = 0; // 信号量编号,0 代表第一个信号量。
 sem_b.sem_op = value; // P 操作的 value 必须小于 0。
 sem_b.sem_flg = m_sem_flg;
 if (semop(m_semid,&sem_b,1) == -1) { perror("p semop()"); return false; }
 return true;
 }
 // 信号量的 V 操作(把信号量的值减 value)。
 bool csemp::post(short value)
 {
 if (m_semid==-1) return false;
 struct sembuf sem_b;
 sem_b.sem_num = 0; // 信号量编号,0 代表第一个信号量。
 sem_b.sem_op = value; // V 操作的 value 必须大于 0。
 sem_b.sem_flg = m_sem_flg;
 if (semop(m_semid,&sem_b,1) == -1) { perror("V semop()"); return false; }
 return true;
 }
 // 获取信号量的值,成功返回信号量的值,失败返回-1。
 int csemp::getvalue()
 {
 return semctl(m_semid,0,GETVAL);
 }
 // 销毁信号量。
 bool csemp::destroy()
 {
 if (m_semid==-1) return false;
 if (semctl(m_semid,0,IPC_RMID) == -1) { perror("destroy semctl()"); return false; }
 return true;
 }
 csemp::~csemp()
 {
 }
 八、makefile
 all:demo1 demo2 demo3 incache outcache
 demo1:demo1.cpp _public.h _public.cpp
 g++ -g -o demo1 demo1.cpp _public.cpp
 demo2:demo2.cpp _public.h _public.cpp
 g++ -g -o demo2 demo2.cpp _public.cpp
 demo3:demo3.cpp _public.h _public.cpp
 g++ -g -o demo3 demo3.cpp _public.cpp
 incache:incache.cpp _public.h _public.cpp
 g++ -g -o incache incache.cpp _public.cpp
 outcache:outcache.cpp _public.h _public.cpp
 g++ -g -o outcache outcache.cpp _public.cpp
 clean:
 rm -f demo1 demo2 demo3 incache outcache
 340、第一个网络通讯程序
 一、网络通讯的流程
 二、demo1.cpp
 /*
 * 程序名:demo1.cpp,此程序用于演示 socket 的客户端
 */
 #include <iostream>
 #include <cstdio>
 #include <cstring>
 #include <cstdlib>
 #include <unistd.h>
 #include <netdb.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <arpa/inet.h>
 using namespace std;
 int main(int argc,char *argv[])
 {
 if (argc!=3)
 {
 cout << "Using:./demo1 服务端的 IP 服务端的端口\nExample:./demo1 192.168.101.139
 5005\n\n";
 return -1;
 }
 // 第 1 步:创建客户端的 socket。
 int sockfd = socket(AF_INET,SOCK_STREAM,0);
 if (sockfd==-1)
 {
 perror("socket"); return -1;
 }
 // 第 2 步:向服务器发起连接请求。
 struct hostent* h; // 用于存放服务端 IP 的结构体。
 if ( (h = gethostbyname(argv[1])) == 0 ) // 把字符串格式的 IP 转换成结构体。
 {
 cout << "gethostbyname failed.\n" << endl; close(sockfd); return -1;
 }
 struct sockaddr_in servaddr; // 用于存放服务端 IP 和端口的结构体。
 memset(&servaddr,0,sizeof(servaddr));
 servaddr.sin_family = AF_INET;
 memcpy(&servaddr.sin_addr,h->h_addr,h->h_length); // 指定服务端的 IP 地址。
 servaddr.sin_port = htons(atoi(argv[2])); // 指定服务端的通信端口。
 if (connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr))!=0) // 向服务端发起连
 接清求。
 {
 perror("connect"); close(sockfd); return -1;
 }
 // 第 3 步:与服务端通讯,客户发送一个请求报文后等待服务端的回复,收到回复后,再发下一
 个请求报文。
 char buffer[1024];
 for (int ii=0;ii<3;ii++) // 循环 3 次,将与服务端进行三次通讯。
 {
 int iret;
 memset(buffer,0,sizeof(buffer));
 sprintf(buffer,"这是第%d 个超级女生,编号%03d。",ii+1,ii+1); // 生成请求报文内容。
 // 向服务端发送请求报文。
 if ( (iret=send(sockfd,buffer,strlen(buffer),0))<=0)
 {
 perror("send"); break;
 }
 cout << "发送:" << buffer << endl;
 memset(buffer,0,sizeof(buffer));
 // 接收服务端的回应报文,如果服务端没有发送回应报文,recv()函数将阻塞等待。
 if ( (iret=recv(sockfd,buffer,sizeof(buffer),0))<=0)
 {
 cout << "iret=" << iret << endl; break;
 }
 cout << "接收:" << buffer << endl;
 sleep(1);
 }
 // 第 4 步:关闭 socket,释放资源。
 close(sockfd);
 }
 三、demo2.cpp
 /*
 * 程序名:demo2.cpp,此程序用于演示 socket 通信的服务端
 */
 #include <iostream>
 #include <cstdio>
 #include <cstring>
 #include <cstdlib>
 #include <unistd.h>
 #include <netdb.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <arpa/inet.h>
 using namespace std;
 int main(int argc,char *argv[])
 {
 if (argc!=2)
 {
 cout << "Using:./demo2 通讯端口\nExample:./demo2 5005\n\n"; // 端口大于 1024,
 不与其它的重复。
 cout << "注意:运行服务端程序的 Linux 系统的防火墙必须要开通 5005 端口。\n";
 cout << " 如果是云服务器,还要开通云平台的访问策略。\n\n";
 return -1;
 }
 // 第 1 步:创建服务端的 socket。
 int listenfd = socket(AF_INET,SOCK_STREAM,0);
 if (listenfd==-1)
 {
 perror("socket"); return -1;
 }
 // 第 2 步:把服务端用于通信的 IP 和端口绑定到 socket 上。
 struct sockaddr_in servaddr; // 用于存放服务端 IP 和端口的数据结构。
 memset(&servaddr,0,sizeof(servaddr));
 servaddr.sin_family = AF_INET; // 指定协议。
 servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // 服务端任意网卡的 IP 都可以用于通讯。
 servaddr.sin_port = htons(atoi(argv[1])); // 指定通信端口,普通用户只能用 1024 以上的
 端口。
 // 绑定服务端的 IP 和端口。
 if (bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr)) != 0 )
 {
 perror("bind"); close(listenfd); return -1;
 }
 // 第 3 步:把 socket 设置为可连接(监听)的状态。
 if (listen(listenfd,5) != 0 )
 {
 perror("listen"); close(listenfd); return -1;
 }
 // 第 4 步:受理客户端的连接请求,如果没有客户端连上来,accept()函数将阻塞等待。
 int clientfd=accept(listenfd,0,0);
 if (clientfd==-1)
 {
 perror("accept"); close(listenfd); return -1;
 }
 cout << "客户端已连接。\n";
 // 第 5 步:与客户端通信,接收客户端发过来的报文后,回复 ok。
 char buffer[1024];
 while (true)
 {
 int iret;
 memset(buffer,0,sizeof(buffer));
 // 接收客户端的请求报文,如果客户端没有发送请求报文,recv()函数将阻塞等待。
 // 如果客户端已断开连接,recv()函数将返回 0。
 if ( (iret=recv(clientfd,buffer,sizeof(buffer),0))<=0)
 {
 cout << "iret=" << iret << endl; break;
 }
 cout << "接收:" << buffer << endl;
 strcpy(buffer,"ok"); // 生成回应报文内容。
 // 向客户端发送回应报文。
 if ( (iret=send(clientfd,buffer,strlen(buffer),0))<=0)
 {
 perror("send"); break;
 }
 cout << "发送:" << buffer << endl;
 }
 // 第 6 步:关闭 socket,释放资源。
 close(listenfd); // 关闭服务端用于监听的 socket。
 close(clientfd); // 关闭客户端连上来的 socket。
 }
  
