Linux网络编程学习笔记-简单点对点聊天程序--6

    xiaoxiao2021-03-25  112

    服务器端套接字分两种,一种是监听套接字,一个是已连接套接字。客户端只有已连接套接字。 监听套接字主要用来接受三次握手数据,一旦三次握手完成了,那么就将其放到已连接队列中,accpet()就可以从中返回一个连接,返回的这个连接被称之为已连接套接字,是用来和客户端进行通信的,并不能接受连接,为主动套接字。 因此一个服务器端有3个客户机连接时,服务器端就有3个不同的已连接套接字,1个监听套接字。

    下面是点对点聊天程序的实现:

    /*服务器端程序*/ #include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #include <fcntl.h> #include <sys/shm.h> #define MYPORT 8887 #define QUEUE 20 #define BUFFER_SIZE 1024 #define ERR_EXIT(m) \ do \ { \ perror(m); \ exit(EXIT_FAILURE); \ } while(0) int do_service(int conn) { char recvbuf[BUFFER_SIZE]={0}; memset(recvbuf,0,sizeof(recvbuf)); int length = recv(conn,recvbuf,sizeof(recvbuf),0); if(length == 0){//客户端关闭的情况 //signal(SIGUSR1,handler); printf("client close by accient\n"); return 0; } if(length < 0){ //如果失败 ERR_EXIT("recv"); return 0; } if(strcmp(recvbuf,"exit\n")==0) return 0; else{ fputs(recvbuf,stdout); return 1; } } int main() { //定义客户端套接字 int sock_ser = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);//最后一位可为0,自动 if(sock_ser <0)//如果失败 ERR_EXIT("socket"); //定义sockaddr_in struct sockaddr_in addr_ser; addr_ser.sin_family = AF_INET; addr_ser.sin_port = htons(MYPORT); addr_ser.sin_addr.s_addr = htonl(INADDR_ANY); //开启地址重复利用 int on = 1; int rel_set = setsockopt(sock_ser,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)); if(rel_set < 0)//如果失败 ERR_EXIT("reuseaddr"); //bind 绑定 int bd = bind(sock_ser,(struct sockaddr*)&addr_ser,sizeof(addr_ser)); if(bd < 0)//如果失败 ERR_EXIT("bind"); //listen 监听 int ln = listen(sock_ser,SOMAXCONN);//listen函数将套接字从主动套接字变成被动套接字;主动套接字主要用来发起连接,而被动套接字用来接受连接 //第二个参数规定能够并发连接的最大数目 =未完成连接数目+ 已完成连接数目: if(ln < 0) //如果错误 ERR_EXIT("listen"); /* 开始定义客户端套接字 */ struct sockaddr_in addr_cli; socklen_t len = sizeof(addr_cli); //使用进程处理多并发 pid_t pid; while(1){ //accept 接收 int conn = accept(sock_ser,(struct sockaddr*)&addr_cli,&len); printf("ip=%s,port=%d\n",inet_ntoa(addr_cli.sin_addr),ntohs(addr_cli.sin_port));//新增打印通信ip和端口 if(conn < 0) //如果失败 ERR_EXIT("accept"); //创建父进程--发送数据 pid = fork(); if(pid == -1) ERR_EXIT("fork"); if(pid == 0)//创建成功 { char sendbuf[BUFFER_SIZE]={0}; while(fgets(sendbuf,sizeof(sendbuf),stdin) != NULL){ send(conn,sendbuf,sizeof(sendbuf),0); memset(sendbuf,0,sizeof(sendbuf)); } printf("child close \n"); exit(EXIT_SUCCESS); close(conn); } else { while(do_service(conn)); printf("parent close\n"); exit(EXIT_SUCCESS); close(conn); } } return 0; } #include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #include <fcntl.h> #include <sys/shm.h> #include <signal.h> #define MYPORT 8887 #define BUFFER_SIZE 1024 #define ERR_EXIT(m) \ do \ { \ perror(m); \ exit(EXIT_FAILURE); \ } while(0) void handler(int sig) { printf("recv a signal =%d\n",sig); exit(EXIT_SUCCESS); } int main() { //定义客户端socket int sock_cli = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); if(sock_cli < 0 )//如果失败 ERR_EXIT("socket"); //定义sockaddr struct sockaddr_in addr_cli; addr_cli.sin_family = AF_INET; addr_cli.sin_port = htons(MYPORT); addr_cli.sin_addr.s_addr = inet_addr("127.0.0.1"); int conn = connect(sock_cli,(struct sockaddr*)&addr_cli,sizeof(addr_cli)); if(conn < 0) ERR_EXIT("connect"); char recvbuf[BUFFER_SIZE]={0}; char sendbuf[BUFFER_SIZE]={0}; pid_t pid; pid = fork(); if(pid == -1) ERR_EXIT("fork"); if(pid == 0)//发送数据 { while(1){ memset(recvbuf,0,sizeof(recvbuf)); int length = recv(sock_cli,recvbuf,sizeof(recvbuf),0); if(length <0) ERR_EXIT("recv"); else if(length == 0){ printf("peer close\n"); break; } fputs(recvbuf,stdout); } close(conn); kill(getppid(),SIGUSR1); } else { while(fgets(sendbuf,sizeof(sendbuf),stdin)!=0){ send(sock_cli,sendbuf,sizeof(sendbuf),0);//发送 memset(sendbuf,0,sizeof(sendbuf)); } } close(conn); return 0; }
    转载请注明原文地址: https://ju.6miu.com/read-5210.html

    最新回复(0)