国内最全IT社区平台 联系我们 | 收藏本站
华晨云阿里云优惠2
您当前位置:首页 > php开源 > php教程 > Socket 编程实践(5) --p2p聊天程序设计与实现

Socket 编程实践(5) --p2p聊天程序设计与实现

来源:程序员人生   发布时间:2015-01-02 09:56:17 阅读次数:3098次

1个短连接的client

//短链接客户端 int main() { int loopCount = 20; char sendBuf[BUFSIZ] = {0}; char recvBuf[BUFSIZ] = {0}; for (int i = 0; i < loopCount; ++i) { sprintf(sendBuf,"Hello Server %d ",i); //创建新的套接字 int sockfd = socket(AF_INET,SOCK_STREAM,0); if (sockfd == ⑴) { err_exit("socket error"); } //填写好服务器地址及其端口号 struct sockaddr_in serverAddr; serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(8002); //本机测试,填写127.0.0.1(回环地址) serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); //连接server if (connect(sockfd,(struct sockaddr *)&serverAddr,sizeof(serverAddr)) == ⑴) { err_exit("connect error"); } //向server发送数据 if (write(sockfd,sendBuf,strlen(sendBuf)) == ⑴) { err_exit("write socket error"); } int readCount = 0; //从server接收数据 if ((readCount = read(sockfd,recvBuf,sizeof(recvBuf))) < 0) { err_exit("read socket error"); } //将其回写到终端 write(STDOUT_FILENO,recvBuf,strlen(recvBuf)); close(sockfd); } return 0; }


注:server端基于上1篇博客中的代码


点对点聊天程序设计与实现

点对点聊天程序功能说明:

 

 

代码实现与说明

//serever端完全代码与说明 #include "commen.h" int main() { //安装信号接收函数 signal(SIGUSR1,onSignal); //创建监听套接字 int sockfd = socket(AF_INET,SOCK_STREAM,0); if (sockfd == ⑴) { err_exit("socket error"); } //添加地址复用 int optval = 1; if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(optval)) == ⑴) { err_exit("setsockopt SO_REUSEADDR error"); } //将监听套接字绑定本机 struct sockaddr_in serverAddr; serverAddr.sin_family = AF_INET; //该行可以删除 serverAddr.sin_port = htons(8001); serverAddr.sin_addr.s_addr = INADDR_ANY; //绑定本机的任意1个IP地址 if (bind(sockfd,(struct sockaddr *)&serverAddr,sizeof(serverAddr)) == ⑴) { err_exit("bind error"); } //启用监听套接字 //1旦调用了listen,则sockfd编程被动套接字 -> 等待客户真个连接(只能接受连接,不能发送连接) if (listen(sockfd,SOMAXCONN) == ⑴) { err_exit("listen error"); } //如果没有客户端链接的来到,则该系统调用会1直阻塞 struct sockaddr_in peerAddr; socklen_t peerLen = sizeof(peerAddr); int peerSockfd = accept(sockfd, (struct sockaddr *)&peerAddr,&peerLen); if (peerSockfd == ⑴) { err_exit("accept error"); } //客户端来到 cout << "Client Connected:" << endl; cout << " peerAddr.sin_addr: " << inet_ntoa(peerAddr.sin_addr) << endl; cout << " peerAddr.sin_port: " << ntohs(peerAddr.sin_port) << endl; //创建子进程 pid_t pid = fork(); if (pid == ⑴) { err_exit("fork error"); } //父进程:从客户端接收数据 -> 打印到屏幕 if (pid > 0) { close(STDIN_FILENO); //关闭没用的文件描写符 char recvBuf[BUFSIZ] = {0}; int readCount = 0; //从客户端接收数据 while ((readCount = read(peerSockfd,recvBuf,sizeof(recvBuf))) > 0) { recvBuf[readCount] = 0; //将其打印到屏幕 fprintf(stdout,"%s",recvBuf); memset(recvBuf,0,sizeof(recvBuf)); } //对端已关闭 if (readCount == 0) { close(peerSockfd); //关闭通讯结点 cout << "peer connect closed" << endl; //发送SIGUSR1信号给子进程,将子进程杀死 kill(pid,SIGUSR1); _exit(0); } //接收毛病 else if (readCount == ⑴) { close(peerSockfd); //发送SIGUSR1信号给子进程,将子进程杀死 kill(pid,SIGUSR1); err_exit("read error"); } } else if (pid == 0) //子进程:从键盘接收数据 -> 写到客户端 { close(STDOUT_FILENO); char sendBuf[BUFSIZ] = {0}; //从键盘接收数据 while (true) { if (fgets(sendBuf,sizeof(sendBuf),stdin) == NULL) { break; } else if (strncmp(sendBuf,"quit",4) == 0) { close(peerSockfd); kill(getppid(),SIGUSR2); break; } //发送到client端 if (write(peerSockfd,sendBuf,strlen(sendBuf)) == ssize_t(⑴)) { close(peerSockfd); err_exit("write socket error"); } memset(sendBuf,0,sizeof(sendBuf)); } } close(sockfd); return 0; }

//client端完全代码与说明 #include "commen.h" int main() { signal(SIGUSR1,onSignal); //创建新的套接字 int sockfd = socket(AF_INET,SOCK_STREAM,0); if (sockfd == ⑴) { err_exit("socket error"); } //填写server端IP地址及其端口号 struct sockaddr_in serverAddr; serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(8001); serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); //连接到server if (connect(sockfd,(struct sockaddr *)&serverAddr,sizeof(serverAddr)) == ⑴) { err_exit("connect error"); } pid_t pid = fork(); if (pid == ⑴) { err_exit("fork error"); } //父进程:从键盘接收数据 -> 将之发送给server端 if (pid > 0) { close(STDOUT_FILENO); char sendBuf[BUFSIZ] = {0}; //从键盘接收数据 while (true) { if (fgets(sendBuf,sizeof(sendBuf),stdin) == NULL) { break; } else if (strncmp(sendBuf,"quit",4) == 0) { close(sockfd); //发送SIGUSR1信号给子进程,将其关闭 kill(pid,SIGUSR1); _exit(0); } //发送到server端 if (write(sockfd,sendBuf,strlen(sendBuf)) == ssize_t(⑴)) { close(sockfd); err_exit("write socket error"); } memset(sendBuf,0,sizeof(sendBuf)); } } else if (pid == 0) //子进程:从server端接收数据,将其打印到屏幕 { close(STDIN_FILENO); char recvBuf[BUFSIZ] = {0}; int readCount = 0; //从server端接收数据 while ((readCount = read(sockfd,recvBuf,sizeof(recvBuf))) > 0) { recvBuf[readCount] = 0; //将其打印到屏幕 fprintf(stdout,"%s",recvBuf); memset(recvBuf,0,sizeof(recvBuf)); } if (readCount == 0) { close(sockfd); cout << "peer connect closed" << endl; //发送SIGUSR2信号给父进程,将其关闭 kill(getppid(),SIGUSR2); _exit(0); } else if (readCount == ⑴) { close(sockfd); err_exit("read error"); } } return 0; }


可以看出,此时既没有端口占用,也没有僵尸进程!



-commen.h

#ifndef COMMEN_H_INCLUDED #define COMMEN_H_INCLUDED #include <unistd.h> #include <signal.h> #include <errno.h> #include <fcntl.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/stat.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/msg.h> #include <sys/sem.h> #include <sys/socket.h> #include <arpa/inet.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <iostream> using namespace std; void err_exit(std::string str) { perror(str.c_str()); exit(EXIT_FAILURE); } struct SendStruct { int type; char text[BUFSIZ]; }; void onSignal(int signalNumber) { switch (signalNumber) { case SIGUSR1: cout << "child receive SIGUSR1" << signalNumber << endl; _exit(0); case SIGUSR2: cout << "parent receive SIGUSR2: " << signalNumber << endl; _exit(0); default: cout << "RECV OTHRER SIGNAL" << endl; } } #endif // COMMEN_H_INCLUDED

附-Makefile

CC = g++ CPPFLAGS = -Wall -g -pthread BIN = server client SOURCES = $(BIN.=.cpp) .PHONY: clean all all: $(BIN) $(BIN): $(SOURCES) clean: -rm -rf $(BIN) bin/ obj/ core

生活不易,码农辛苦
如果您觉得本网站对您的学习有所帮助,可以手机扫描二维码进行捐赠
程序员人生
------分隔线----------------------------
分享到:
------分隔线----------------------------
关闭
程序员人生