【linux高级程序设计】(第十三章)Linux Socket网络编程基础 3

时间:2021-07-06 01:06:13

使用之前的函数实现的简单聊天程序

TCP协议

双方实时发送/接收消息

 

实现后的问题:

  可能是我虚拟机的IP地址配得有问题吧。在一台电脑上面开两个终端,用127.0.0.1的IP收发可以互通。但是两个虚拟机就不行了,用192.168的IP段,能够ping通但是代码接收不到消息。

  还有,两个进程都是接收到消息后,需要我自己按一下回车才能发送消息。

 

服务器端代码:

#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<sys/socket.h>
#include<resolv.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#define MAXBUF 1024
int main(int argc, char *argv[])
{
    int pid;
    int sockfd, new_fd;
    socklen_t len;
    struct sockaddr_in my_addr, their_addr;
    unsigned int myport, lisnum;
    char buf[MAXBUF + 1];
    if(argv[2])
        myport = atoi(argv[2]);  //命令行字符串转为整数,端口
    else 
        myport = 7575;           //默认端口
    
    if(argv[3])
        lisnum = atoi(argv[3]);  //监听队列的大小
    else
        lisnum = 5;
    
    //创建socket对象, IPv4, TCP, 默认协议
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)   //创建socket对象
    {
        perror("socket");
        exit(EXIT_FAILURE);
    }
    
    bzero(&my_addr, sizeof(my_addr));
    my_addr.sin_family = AF_INET;               //地址协议
    my_addr.sin_port = htons(myport);           //地址端口
    if(argv[1])
        my_addr.sin_addr.s_addr = inet_addr(argv[1]);   //指定IP地址 从点分十进制字符串转为32位二进制
    else
        my_addr.sin_addr.s_addr = INADDR_ANY;   //否则设置为本机任意地址
    
    char mybuf[128];
    inet_ntop(AF_INET, &my_addr.sin_addr.s_addr, mybuf, 128);
    printf("the ip is '%s'\n", mybuf);
    //绑定地址信息
    if(bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1)
    {
        perror("bind");
        exit(EXIT_FAILURE);
    }
    
    //监听网络
    if(listen(sockfd, lisnum) == -1)
    {
        perror("listen");
        exit(EXIT_FAILURE);
    }
    printf("wait for connect\n");
    len = sizeof(struct sockaddr);
    
    //阻塞等待连接
    if((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &len)) == -1)
    {
        perror("accept");
        exit(EXIT_FAILURE);
    }
    else   //打印接收到的信息
    {        
        printf("server: got connection from %s, port %d, socket %d\n", inet_ntoa(their_addr.sin_addr), ntohs(their_addr.sin_port), new_fd);
    }
    
    //创建新进程
    if(-1 == (pid = fork()))
    {
        perror("fork");
        exit(EXIT_FAILURE);
    }
    else if(0 == pid)   //子进程用于发送消息
    {
        while(1)
        {
            bzero(buf, MAXBUF + 1);
            printf("input the message to send:");
            fgets(buf, MAXBUF, stdin);
            if(!strncasecmp(buf, "quit", 4))
            {
                printf("i will close the connect!\n");
                break;
            }
            len = send(new_fd, buf, strlen(buf) - 1, 0);
            if(len < 0)
            {
                printf("message '%s' send failure! errno code is %d, errno message is '%s'\n", buf, errno, strerror(errno));
                break;
            }
        }
    }
    else  //父进程用于接收消息 
    {
        while(1)
        {
            bzero(buf, MAXBUF + 1);
            len = recv(new_fd, buf, MAXBUF, 0);
            if(len > 0)
            {
                printf("message recv successful : '%s', %dByte recv\n", buf, len);
            }
            else if(len < 0)
            {
                printf("recv failure! errno code is %d, errno message is '%s'\n", errno, strerror(errno));
                break;
            }
            else
            {
                printf("the other one close quit\n");
                break;
            }
        }
    }
    
    close(new_fd);
    close(sockfd);
    return 0;
}

 

 

客户端代码:

#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<sys/socket.h>
#include<resolv.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#define MAXBUF 1024
int main(int argc, char **argv)
{
    int sockfd, len;
    struct sockaddr_in dest;
    char buffer[MAXBUF + 1];
    if(argc != 3)
    {
        printf(" error format, it must be :\n \t\t%s IP port\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    
    //创建socket对象
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("Socket");
        exit(errno);
    }
    printf("socket created\n");
    bzero(&dest, sizeof(dest));
    dest.sin_family = AF_INET;             //地址协议
    dest.sin_port = htons(atoi(argv[2]));  //对方端口
    //对方IP地址
    if(inet_aton(argv[1], (struct in_addr *)&dest.sin_addr.s_addr) == 0)  
    {
        perror("argv[1]");
        exit(errno);
    }
    //发起连接
    if(connect(sockfd, (struct sockaddr *)&dest, sizeof(dest)) == -1)
    {
        perror("Connect");
        exit(errno);
    }
    printf("server connected\n");
    pid_t pid;
    
    //创建子进程
    if(-1 == (pid = fork()))
    {
        perror("fork");
        exit(errno);
    }
    else if(pid == 0)       //子进程用于数据接收
    {
        while(1)
        {
            bzero(buffer, MAXBUF + 1);
            len = recv(sockfd, buffer, MAXBUF, 0);
            if(len > 0)
            {
                printf("recv successful:'%s', %d byte recv\n", buffer, len);
            }
            else if(len < 0)
            {
                perror("recv");
                break;
            }
            else
            {
                printf("the other one close, quit\n");
                break;
            }
        }
    }
    else   //父进程用于数据发送
    {
        while(1)
        {
            bzero(buffer, MAXBUF + 1);
            printf("input the message to send:");
            fgets(buffer, MAXBUF, stdin);
            if(!strncasecmp(buffer, "quit", 4))
            {
                printf("i will close the connect!\n");
                break;
            }
            len = send(sockfd, buffer, strlen(buffer) - 1, 0);
            if(len < 0)
            {
                printf("message '%s' send failure! errno code is %d, errno message is '%s'\n", buffer, errno, strerror(errno));
                break;
            }
        }
    }
    close(sockfd);
    return 0;
}