[置顶] socket编程之点对点聊天程序

时间:2022-11-21 23:58:11

点对点聊天程序并解决上一篇中父进程退出,子进程不退出情况

p2psrv.c:

#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<signal.h>//解决父进程退出,子进程不退出

#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#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);//将子进程退出

}
void do_service(int conn)
{
char recvbuf[1024];
while(1){
memset(recvbuf,0,sizeof(recvbuf));//初始化recvbuf
int ret=read(conn,recvbuf,sizeof(recvbuf));//函数从打开的文件,设备中读取数据,返回读取的字节数。
if(ret==0)
{
printf("client_close\n");
break;
}
else if(ret==-1)
{
ERR_EXIT("read");
}
fputs(recvbuf,stdout);
write(conn,recvbuf,ret);//buf中数据被复制到了TCP发送缓冲区
}
}
int main(void)
{
int listenfd;
/*if((listenfd=socket(AF_INET,SOCK_STEAM,IPPOTO_TCP))<0) */
if((listenfd=socket(AF_INET,SOCK_STREAM,0))<0)
ERR_EXIT("socket");

//IPV4地址结构
struct sockaddr_in servaddr;
memset(&servaddr,0,sizeof(servaddr));
servaddr.sin_family=AF_INET;//地址家族
servaddr.sin_port=htons(5188);//端口,主机转网络
/*servaddr.sin_addr.s_addr=inet_addr("127.0.0.1");*/
/*inet_aton("127.0.0.1",&servaddr.sin_addr);*/
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
int on=1;
if(setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on))<0)
ERR_EXIT("setsockopt");

if(bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0)
ERR_EXIT("bind");


if(listen(listenfd,SOMAXCONN)<0)
ERR_EXIT("listen");

struct sockaddr_in peeraddr;
socklen_t peerlen =sizeof(peeraddr);//typedef int socklen_t
int conn;//已连接套接字
pid_t pid;

if((conn=accept(listenfd,(struct sockaddr*)&peeraddr,&peerlen))<0)
ERR_EXIT("accept");

printf("ip=%s port=%d\n",inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port));

pid=fork();
if(pid==-1)
ERR_EXIT("fork");
if(pid==0)//发送数据进程
{
signal(SIGUSR1,handler);
char sendbuf[1024]={0};
while(fgets(sendbuf,sizeof(sendbuf),stdin)!=NULL)//从标准输入获取数据
{
write(conn,sendbuf,strlen(sendbuf));//发送到TCP缓冲区
memset(sendbuf,0,sizeof(sendbuf));
}

exit(EXIT_SUCCESS);//将子进程退出,要不它会fork()
}
else//父进程用来获取数据(接收数据进程)
{
char recvbuf[1024];
while(1){
memset(recvbuf,0,sizeof(recvbuf));//初始化recvbuf
int ret=read(conn,recvbuf,sizeof(recvbuf));//函数从打开的文件,设备中读取数据,返回读取的字节数。
if(ret==0)
{
printf("peer_close\n");
break;//否则一直输出“peer_close”
}
else if(ret==-1)
{
ERR_EXIT("read");
}
fputs(recvbuf,stdout);

// write(conn,recvbuf,ret);//buf中数据被复制到了TCP发送缓冲区
}
printf("parent close\n");
kill(pid,SIGUSR1);//父进程向子进程发送信号
exit(EXIT_SUCCESS);
}

return 0;
}

p2pcli:

#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<signal.h>

#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#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 sock;
/*if((listenfd=socket(AF_INET,SOCK_STEAM,IPPOTO_TCP))<0) */
if((sock=socket(AF_INET,SOCK_STREAM,0))<0)
ERR_EXIT("socket");

//IPV4地址结构
struct sockaddr_in servaddr;
memset(&servaddr,0,sizeof(servaddr));
servaddr.sin_family=AF_INET;//地址家族
servaddr.sin_port=htons(5188);//端口,主机转网络
servaddr.sin_addr.s_addr=inet_addr("127.0.0.1");
/*inet_aton("127.0.0.1",&servaddr.sin_addr);*/


if(connect(sock,(struct sockaddr*)&servaddr,sizeof(servaddr))<0)
ERR_EXIT("connect");

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 ret=read(sock,recvbuf,sizeof(recvbuf));
if(ret==-1)
ERR_EXIT("read");
else if(ret==0)
{

printf("peer close!\n");
break;
}
fputs(recvbuf,stdout);
}
close(sock);
kill(getppid(),SIGUSR1);
}
else//发送数据
{
signal(SIGUSR1,handler);
char sendbuf[1024]={0};
while(fgets(sendbuf,sizeof(sendbuf),stdin) !=NULL){
write(sock,sendbuf,strlen(sendbuf));//发送
memset(sendbuf,0,sizeof(sendbuf));

}
close(sock);

}
return 0;


}