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


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

波比源码 – 精品源码模版分享 | www.bobi11.com
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
7. 本站源码并不保证全部能正常使用,仅供有技术基础的人学习研究,请谨慎下载
8. 如遇到加密压缩包,请使用WINRAR解压,如遇到无法解压的请联系管理员!

波比源码 » Socket 编程实践(5) –p2p聊天程序设计与实现

发表评论

Hi, 如果你对这款模板有疑问,可以跟我联系哦!

联系站长
赞助VIP 享更多特权,建议使用 QQ 登录
喜欢我嘛?喜欢就按“ctrl+D”收藏我吧!♡