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

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

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;
}
时间: 2025-01-18 07:03:13

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

javascript高级程序设计 第十三章--事件

javascript高级程序设计 第十三章--事件js与HTML的交互就是通过事件实现的,事件就是文档或浏览器窗口中发生的一些特定的交互瞬间. 事件流:事件流描述的是从页面中接收事件的顺序,IE的是事件冒泡流,Netscape的是事件捕获流,这个两个是完全相反的事件流概念. 事件冒泡:由最具体的元素接收,然后逐级向上传播到更高级的节点,即事件沿DOM树向上传播,直到document对象. 事件捕获:不大具体的节点应该更早接收到事件,相当于沿DOM节点树向下级传播直到事件的实际目标,在浏览器中,是

Linux程序设计学习笔记----Socket网络编程基础之TCP/IP协议簇

转载请注明出处: ,谢谢! 内容提要 本节主要学习网络通信基础,主要涉及的内容是: TCP/IP协议簇基础:两个模型 IPv4协议基础:IP地址分类与表示,子网掩码等 IP地址转换:点分十进制\二进制 TCP/IP协议簇基础 OSI模型 我们知道计算机网络之中,有各种各样的设备,那么如何实现这些设备的通信呢? 显然是通过标准的通讯协议,但是,整个网络连接的过程相当复杂,包括硬件.软件数据封包与应用程序的互相链接等等,如果想要写一支将联网全部功能都串连在一块的程序,那么当某个小环节出现问题时,整只

嵌入式 Linux网络编程(一)——Socket网络编程基础

嵌入式 Linux网络编程一--Socket网络编程基础 一.Socket简介 1.网络中进程间通信 本机进程使用进程号区别不同的进程进程间通信方式有管道.信号.消息队列.共享内存.信号量等.网络中进程间的通信首先需要识别进程所在主机在网络中的唯一标识即网络层的IP地址主机上的进程可以通过传输层的协议与端口号识别. 2.Socket原理 Socket是应用层与TCP/IP协议族通信的中间软件抽象层是一种编程接口.Socket屏蔽了不同网络协议的差异支持面向连接(Transmission Cont

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

BSD Socket网络编程API 创建socket对象 int socket (int __domain, int __type, int __protocol) :成功返回socket文件描述符,失败返回-1. 参数1:socket对象使用的地址簇或协议簇  常用的有PF_LOCAL(本机通信).PF_INET(IPv4协议簇).PF_INET6(IPv6协议簇) 参数2:socket的类型.常见有:面向连接的数据流方式:面向无连接的数据报方式 参数3:标识采用哪一种协议,0表示默认. 绑定

python全栈开发从入门到放弃之socket网络编程基础

网络编程基础 一 客户端/服务器架构 1.硬件C/S架构(打印机) 2.软件C/S架构 互联网中处处是C/S架构 如黄色网站是服务端,你的浏览器是客户端(B/S架构也是C/S架构的一种) 腾讯作为服务端为你提供视频,你得下个腾讯视频客户端才能看它的视频) C/S架构与socket的关系: 我们学习socket就是为了完成C/S架构的开发 为何学习socket一定要先学习互联网协议: 1.首先:本节课程的目标就是教会你如何基于socket编程,来开发一款自己的C/S架构软件 2.其次:C/S架构的

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

网络调试工具 tcpdump 功能:打印指定网络接口中与布尔表达式匹配的报头信息 关键字: ①类型:host(默认).net.port host 210.27.48.2 //指明是一台主机 net 202.0.0.0 //指明是一个网络 port 23 //指明端口号 ②确认传输方向:src. dst. dst or src. dst and src src 210.27.48.2 //ip包中源地址为此值 dst net 202.0.0.0 //目的网络地址是202.0.0.0 ③协议关键字:

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

IP地址定义: struct in_addr{ __u32 s_addr; }; in_addr_t  inet_addr (__const char * __cp) :把点分十进制IP地址字符串转换为32位IP地址(网络存储顺序). in_addr_t inet_network (__const char * __cp) :把点分十进制IP地址字符串转换为32位IP地址(主机字节顺序). char * inet_ntoa (struct in_addr_in) :把32位网络字节顺序的IP地址

JAVASE学习笔记:第十三章 多线程和网络编程

一.进程是由线程组成的 调用线程:1.继承thread类或者实现rannable接口 2.重写run方法 3.创建线程 4.通过start方法开启线程 thread t1=new thread(runnable xx); 线程的状态:1.新建状态(new)  2.可执行状态(start获取CPU的使用权限)  3.执行状态(执行完返回第2步) 4.死亡状态 5.当线程遇到输入流和sleep时,执行状态变成阻塞状态 Thread.activeCount()  当前活动线程数 Thread.curr

windows socket网络编程基础知识

下面介绍网络7层协议在WINDOWS的实现: 7层协议 WIN系统 ________________________________________ 7 应用层 7 应用程序 ________________________________________________ 6 表示层 6 WINSOCK API(DLL) ___________________________________________ 5 会话层 5 SPI(DLL) ___________________________