点对点聊天室为人们进行交流提供了一个平台,且其具有极高的私密性与便捷性。通过提供完善的网络聊天系统,可以达到人与人之间的交流与联系的目的。
VMware Workstation 15 Pro
Red Hat Enterprise Linux 5
每人一台计算机并能够连入局域网
(1)服务器:
① 接受客户端发送过来的数据并显示
② 接受键盘输入的数据,并发送给客户端
③ 客户端关闭,服务器端的进程也将全部退出。
(2)客户端:
① 接受服务器发送过来的数据并显示
② 接受键盘输入的数据,并发送给服务器
③ 服务器关闭,客户端的进程也将全部退出。
#include //是在程序编译之前要处理的内容,称为编译预处理命令。
#include //语句是指将 stdlib.h 包含到程序里面。
#include //是在程序编译之前要处理的内容,与字符串的调用有关。
#include //提供对 POSIX 操作系统 API 的访问功能的头文件的名称。
#include //主要定义了格式转换函数。
#include //提供socket函数及数据结构。
#include //定义了程序执行时如何处理不同的信号。
/*错误重定义*/
#define ERR_EXIT(m)\
do\
{\
perror(m);\//将上一个函数发生错误的原因输出到标准设备。
exit(EXIT_FAILURE);\//
代表异常退出。
}while(0)
/*信号处理函数*/
void handler(int sig)
{
printf("recv
a sig=%d\n", sig);
exit(EXIT_SUCCESS);//
指示程序成功终止
}
/*开始主程序*/
int main(int argc,char *argv[])
{
int listenfd; //定义监听套接字、客户套接字
int connfd;
struct sockaddr_in servaddr;
struct sockaddr_in clntaddr;
socklen_t clntaddr_size;
pid_t pid; //定义线程标记变量
if(argc!=2)
{
printf("usage:%s,\n" ,argv[0]);
exit(1);
}
/*创建服务器端套接字*/
listenfd=socket(PF_INET,SOCK_STREAM,0); //生成一个TCP的socket
if(listenfd==-1)
ERR_EXIT("socket");
/*初始化本地地址信息*/
memset(&servaddr,0,sizeof(servaddr)); //作用是在一段内存块中填充某个给定的值
servaddr.sin_family=AF_INET; //创建套接字时,用该字段指定地址家族
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
//监听客户端的所有地址
servaddr.sin_port=htons(atoi(argv[1]));
/*将地址信息分配给套接字*/
if(bind(listenfd,(struct sockaddr
*)&servaddr,sizeof(servaddr))==-1)
ERR_EXIT("bind");
/*调用listen函数进入等待连接请求状态,此时套接字成为被动套接字,负责监听*/
if(listen(listenfd,5)==-1)
ERR_EXIT("listen");
/*调用accept函数从队头取1个连接请求与客户端建立连接,并返回创建的套接字描述符,conn_sock主要用来与客户进行通信,而之前的serv_sock主要用于监听*/
connfd=accept(listenfd,(struct sockaddr
*)&clntaddr,&clntaddr_size);
if(connfd==-1)
ERR_EXIT("accept");
else
printf("recv connect
ip=%s,port=%d\n",inet_ntoa(clntaddr.sin_addr),ntohs(clntaddr.sin_port)); //输出
pid_t pid;
pid=fork( );//创建子进程
if(pid==-1)
ERR_EXIT("fork");
if(pid>0) //父进程,负责接收客户端发送过来的数据
{
char recvbuf[1024];
while(1)
{
memset(recvbuf,0,sizeof(recvbuf));
int str_len=read(connfd,recvbuf,sizeof(recvbuf));
if(str_len==-1)
ERR_EXIT("read");
if(str_len==0)
{
printf("Client closed\n");
break;
}
printf("Message from client:");
fputs(recvbuf,stdout);
}
close(connfd);
close(listenfd);
printf("parent close\n");
kill(pid, SIGUSR1); //调用kill函数将信号发送给子进程
exit(EXIT_SUCCESS);
}
else if(pid==0)
{
signal(SIGUSR1, handler);//一旦接收到SIGUSR1信号就调用handler函数进行处理
char
sendbuf[1024];
while(fgets(sendbuf,sizeof(sendbuf),stdin)!=NULL)
{
write(connfd,sendbuf,sizeof(sendbuf));
memset(sendbuf,0,sizeof(sendbuf));
}
}
return 0;
}
#include //是在程序编译之前要处理的内容,称为编译预处理命令。
#include //语句是指将 stdlib.h 包含到程序里面。
#include //是在程序编译之前要处理的内容,与字符串的调用有关。
#include //提供对 POSIX 操作系统 API 的访问功能的头文件的名称。
#include //主要定义了格式转换函数。
#include //提供socket函数及数据结构。
#include //定义了程序执行时如何处理不同的信号。
/*错误宏定义*/
#define ERR_EXIT(m)\ //定义错误出口
do\
{\
perror(m);\
exit(EXIT_FAILURE);\ //代表异常退出
}while(0)
/*信号处理函数*/
void handler(int sig)
{
printf("recv
a sig=%d\n", sig);
exit(EXIT_SUCCESS);//指示程序成功终止
}
/*开始主程序*/
int main(int argc,char *argv[])
{
int
sock;
struct sockaddr_in servaddr;// 声明了一个struct
sockaddr_in类型的变量
char
sendbuf[1024];// 定义了一个大小为1024的sendbuf数组
if(argc!=3) //获取信息错误的提示。但是不停止运行任何代码
{
printf("usage:%s,<IP>
<port>\n",argv[0]);
exit(1);
}
/*创建准备连接服务器端的套接字*/
sock=socket(PF_INET,SOCK_STREAM,0); // socket()系统调用,带有三个参数
if(sock==-1)
ERR_EXIT("socket");
memset(&servaddr,0,sizeof(servaddr));
servaddr.sin_family=AF_INET;
//创建套接字时,用该字段指定地址家族,对于TCP/IP协议的,必须设置为AF_INTE。
servaddr.sin_addr.s_addr=inet_addr(argv[1]);
servaddr.sin_port=htons(atoi(argv[2]));
/*与服务器建立连接*/
if(connect(sock,(struct sockaddr *)&servaddr,sizeof(servaddr))==-1)
ERR_EXIT("connect");
else
printf("Connected......\n");
pid_t pid;// 定义了一个pid_t类型的变量pid
pid=fork();//fork()函数返回一个进程号,这个进程号赋给了pid
/*父进程,负责从键盘接收数据,并传输给服务器端*/
if(pid>0)
{
signal(SIGUSR1, handler);//一旦接收到SIGUSR1信号就调用handler函数进行处理
while(fgets(sendbuf,sizeof(sendbuf),stdin)!=NULL)
{
write(sock,sendbuf,sizeof(sendbuf));
memset(sendbuf,0,sizeof(sendbuf));
}
}
/*子进程,负责从服务器接收数据并显示*/
else if(pid==0)
{
char recvbuf[1024];// 定义了一个大小为1024的recvbuf数组
while(1)
{
int str_len=read(sock,recvbuf,sizeof(recvbuf));
if(str_len==0)
{
printf("server closed\n");
break;
}
else if(str_len<0)
ERR_EXIT("read");
printf("Message from
server:");
fputs(recvbuf,stdout);
memset(recvbuf,0,sizeof(recvbuf));
}
close(sock);
kill(getppid( ), SIGUSR1);////调用kill函数将信号发送给
}
else
ERR_EXIT("fork");
return 0;
}