Linux初学第十七天<网络编程三、socket客户端配置及双方消息收发>

一、socket客户端配置步骤

      昨天以及完成了服务器的配置,已经可以让客户端连接,但是还无法达到数据交互,就差一个可以正式达到聊天效果的客户端。在正式编程之前,我们先来回顾一下客户端的编程步骤:
                                                            在这里插入图片描述
其中有一个连接服务的函数connect();并没有学过,来=看看一下这个函数:

1.连接函数connect()

      连接服务器,只用于客户端:
函数原型: int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
参数说明:
                  1. sockfd 网络描述符,为socket() 返回值;
                  2. *addr IP地址和端口的配置结构体,配置需要连接的服务器的IP地址和端口;
                  3. addrlen*addr 的大小;
返回值: 成功返回0;失败返回 -1;

小笔记

      昨天在配置客户端的时候,writeread 使用的描述符是 accept 返回的描述符,但是现在客户端不需要accept 函数,所以客户端的收发,writeread 所使用的描述符是socket() 返回的描述符。下面正式来编写客户端程序。

二、socket客户端配置

      先起一个函数给客户端初始化函数吧:

  #include <arpa/inet.h>
  #include <unistd.h>
  #include <string.h>
  #include <stdlib.h>
  
  int socket_fd;
  void Client_Init(char *ip_Addr,unsigned int port)//客户端初始化
  {
          struct sockaddr_in s_addr;
          memset(&s_addr,0,sizeof( struct sockaddr_in));
          ip_Addr=(char *)malloc(sizeof(char));
          socket_fd=socket(AF_INET,SOCK_STREAM,0);//创建sokcet
          //2.bind()
          s_addr.sin_family=AF_INET;//配置协议为IPv4
          s_addr.sin_port=htons(port);//配置端口
          inet_aton(ip_Addr,&s_addr.sin_addr);//配置IP地址
          
          if(connect(socket_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in))==-1){
                  perror("connect");
                  exit(-1);
          }else {
                  printf("connect server success!\n");
          }
          free(ip_Addr);//释放内存
  }

有了这个函数,方便我们连接服务器IP地址和端口号,后面运行时,带参数输入,就免去因为服务器的IP的改变而改来改去的麻烦。其实到了这里,只要在主函数里调用就可以连接服务器了,我们调用一下:

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

int socket_fd;
void Client_Init(char *ip_Addr,unsigned int port)
{
        struct sockaddr_in s_addr;
        memset(&s_addr,0,sizeof( struct sockaddr_in));

        ip_Addr=(char *)malloc(sizeof(char));
        socket_fd=socket(AF_INET,SOCK_STREAM,0);
        //2.bind()
        s_addr.sin_family=AF_INET;
        s_addr.sin_port=htons(port);
        inet_aton(ip_Addr,&s_addr.sin_addr);
        if(connect(socket_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in))==-1){
                perror("connect");
                exit(-1);
        }else {
                printf("connect server success!\n");
        }
}
int main(int argc,char **argv)
{
	
	if(argc!=3){
                printf("input error!");
                exit(-1);
        }
        Client_Init(argv[1],atoi(argv[2]));
        //write/read
        return 0;
}

连接成功后,会打印connect server success!,为了更加直观一些,我们先改一下服务器的代码:

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int status=10;
int socket_fd;
struct sockaddr_in a_addr;
void Server_Init(char *ip_Addr,unsigned int port)
{

        int bind_ret;
        struct sockaddr_in s_addr;
        ip_Addr=(char *)malloc(sizeof(char ));
        memset(&s_addr,0,sizeof( struct sockaddr_in));
        //1.socket
        socket_fd=socket(AF_INET,SOCK_STREAM,0);

        //2.bind()
        s_addr.sin_family=AF_INET;
        s_addr.sin_port=htons(port);
        inet_aton(ip_Addr,&s_addr.sin_addr);

        bind_ret=bind(socket_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
        free(ip_Addr);
        //3.listen()
        listen(socket_fd,10);
}

int main(int argc,char **argv)
{
        int addrlen;
        int accept_num;
        if(argc!=3){
                printf("input error!\n");
                exit(-1);
        }

        Server_Init(argv[1],atoi(argv[2]));
        //4.accept()
        addrlen=sizeof(struct sockaddr_in);

        memset(&a_addr,0,sizeof( struct sockaddr_in));
	  printf("wait Client...\n");
	   accept_num=accept(socket_fd,(struct sockaddr *)&a_addr,&addrlen);
                if(accept_num==-1){
                        perror("accept");
                }
                printf("Connect client ip=%s\n",inet_ntoa(a_addr.sin_addr));
        while(1);             
        return 0;
}

服务器的IP地址和端口也过参数传入,来运行看看:
在这里插入图片描述

三、实现双方聊天

      说一下思路,先从服务器开始吧:
      服务在listen 之后会卡在accept 处,等待客户端的连接,那么我们就可以在while循环里不断地检测客户端的连接,这么可以达到一个可以连接多个客户端的目的,这个功能先不详细说;连接之后,分别创建子进程来发送数据,和接收数据,这样就可以实现接收和发送两不误。
      客户端也是一样的,在connect()之后,在while循环里分别创建两个子进程,来负责接收和发送。

1.服务器发送和接收消息代码:

 while(1){
                accept_num=accept(socket_fd,(struct sockaddr *)&a_addr,&addrlen);
                if(accept_num==-1){
                        perror("accept");
                }
                printf("Connect client ip=%s\n",inet_ntoa(a_addr.sin_addr));
                //write/read
                if(fork()==0){//创建子进程负责读取
                        while(1){
                                memset(readBUf,0,sizeof(readBUf));

                                s_read=read(accept_num,readBUf,sizeof(readBUf));
                                if(s_read==-1){
                                        perror("read");
                                }else{
                                        printf("read:%s\n",readBUf);
                                }
                        }
                }

                if(fork()==0){//创建子进程 负责发送
                        while(1){
                                memset(msg,0,sizeof(msg));
                                printf("input:");
                                fgets(msg,strlen(msg),stdin);//输入发送内容
                                write(accept_num,msg,strlen(msg));//发送
                        }
                }
        }

2.客户端发送和接收消息代码:

 while(1){
                if(fork()==0){//创建子进程发送
                        while(1){
                                printf("input:");
                                memset(msg,0,sizeof(msg));//每次都清空消息,防止内容重复
                                fgets(msg,sizeof(msg),stdin);
                                write(socket_fd,msg,strlen(msg));
                        }
                }
                if(fork()==0){//创建子进程不断接收
                	while(1){
		                memset(readBUf,0,sizeof(readBUf));//每次都清空消息,防止内容重复
		                s_read=read(socket_fd,readBUf,128);//父进程不断读入
		
		                if(s_read==-1){
		                        perror("read");
		                }else{
		                        printf("Read buf=%s\n",readBUf);
		                }
	                }
            }
        }

3.运行结果

在这里插入图片描述

总结

        以这种思路的来做,就可以做到多方消息收发,但是目前还很难决定服务器在众多客服端中指定的发送,就是我们还无法控制服务器该给谁发送。现在的情况时,服务器在发送一个消息之后,众多客户端会争夺这个消息,就像进程一样,会争夺资源。这个问题需要更深入的学习,但是学习的重点不在此处,没必要去浪费学习时间,以后有时间可以去试着让服务端指定给某个客户端发消息。
        网络的编程会在这里告一段落,明天开始就是整个Linux初学的检验项目,类FTP文件云盘,实现客户端下载或上传服务器的文件。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在计算机网络编程领域中,Linux系统的网络编程技术有着非常重要的作用。如果要对Linux网络编程技术进行深入学习并掌握相关技术,在网络编程的基础知识学习之后,更需要好的网络编程指导书籍,其中之一就是《Linux网络编程》这本pdf。 该PDF以C语言为基础,主题集中在Linux系统下的socket编程。从最基础的使用socket创建TCP/IP连接,再到linux网络编程中比较重要的IO复用技术(如select/poll/epoll/kqueue),再到IPV6编程、网络安全以及多线程程序的编写,都有详细的说明和样例。此外,这本pdf还解释了许多难点读者通常会面临的系统调用和API,比如getaddrinfo、getnameinfo等。 总的来说,这本pdf具备以下七个方面的优点: 1. 适合初学者,从最基础的socket连接开始,循序渐进掌握网络编程技能。 2. 含有丰富的实例代码,读者可以从中学到标准的Linux网络编程模型。 3. 全面介绍IO复用的实现技术,能够有效提高服务端程序的并发能力和处理性能。 4. 在IPv6协议栈的更新和普及的背景下,该pdf更新了原有的IPv4编程技术,并为读者讲解了IPv6编程中需要注意的各种细节和改进。 5. 详细讲解了网络安全方面的内容,使读者了解到许多网络编程的安全问题和如何进行防范。 6. 内容简单易懂,配合详细的图示和实例代码,真正做到"所见所得"。 7. 不仅适合初学者,对于有经验的网络工程师也是一本很有价值的参考书,并能够解决许多实际网络编程场景中出现的问题。 因此,这本pdf对于想要学习Linux网络编程技术,从网络编程基础和IO复用技术的学习到网络安全、多线程程序以及IPv6编程的学习都具有非常大的参考价值,特别是对于初学者来说,经过深入学习后,能够对Linux网络编程技术有更加深入的理解,为参加面试和实际项目工作奠定更坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值