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

8 篇文章 0 订阅
8 篇文章 0 订阅

服务器端套接字分两种,一种是监听套接字,一个是已连接套接字。客户端只有已连接套接字
监听套接字主要用来接受三次握手数据,一旦三次握手完成了,那么就将其放到已连接队列中,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;   
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值