利用java的socket实现一个简单hello/hi聊天程序(代码片段)

Euterpe0511 Euterpe0511     2022-12-23     317

关键词:

 

利用java的Socket实现一个简单hello/hi聊天程序

 

首先,我们来用java实现一个简单的hello/hi聊天程序。在这个程序里,我学习到了怎么用socket套接套接字来进行编程。简单理解了一些关于socket套接字和底层调用的关系。关于java的封装思想,我学会了一些东西,java里真的是万物皆对象。还学到了一点多线程的知识。

 

TCP

 

在这里,不得不先介绍以下TCP。TCP是传输层面向连接的协议。提供了端到端的进程之间的通信方式。TCP在通信之前要先建立连接。这里我们称这个建立连接的过程为“三次握手”。如果想详细了解TCP建立连接和释放连接的过程,请参考我另一篇博客。

 

JavaSocket

 

Socket和ServerSocket类库位于java.net包中。ServerSocket用于服务器端,Socket是建立网络连接时使用的。在连接成功时,应用程序两端都会产生一个Socket实例,操作这个实例,完成所需的会话。对于一个网络连接来说,套接字是平等的,并没有差别,不因为在服务器端或在客户端而产生不同级别。不管是Socket还是ServerSocket它们的工作都是通过SocketImpl类及其子类完成的。抽象类SocketImpl是实现套接字的所有类的通用超类。创建客户端和服务器套接字都可以使用它。

 

Java在调用Socket方法的时候并不能直接调用底层的函数。作为一个高度封装的语言。它只能先调用JVM,然后它在调用操作系统的内核函数来建立Socket连接

 

 

 

Socket

 

这里我们打开了Linux下的Socket函数,这里我们查看到一些基本信息。

 

 

AF_INET这里用的是IPv4

 

SOCK_STREAM是流式套接字,基于面向字节流的TCP

 

SOCK_DGRAM是数据报套接字,基于面向数据报的UDP

 

Linux中万物皆文件,套接字只是其中文件之间的一种通信方式,虽然是不同主机上的文件。通信双方的主机各自打开一个套接字,套接字之间通过网络来连接,这样两个主机上的进程就可以交换文件信息了。

 

下面是socket调用的过程:

 

 

socket()调用sys_socketcall()系统调用。bind,connect等等函数都需要sys_socketcall()作为入口。

 

SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)

    unsigned long a[AUDITSC_ARGS];
    unsigned long a0, a1;
    int err;
    unsigned int len;

    if (call < 1 || call > SYS_SENDMMSG)
        return -EINVAL;
    call = array_index_nospec(call, SYS_SENDMMSG + 1);

    len = nargs[call];
    if (len > sizeof(a))
        return -EINVAL;

    /* copy_from_user should be SMP safe. */
    if (copy_from_user(a, args, len))
        return -EFAULT;

    err = audit_socketcall(nargs[call] / sizeof(unsigned long), a);
    if (err)
        return err;

    a0 = a[0];
    a1 = a[1];

    switch (call) 
    case SYS_SOCKET:
        err = __sys_socket(a0, a1, a[2]);
        break;
    case SYS_BIND:
        err = __sys_bind(a0, (struct sockaddr __user *)a1, a[2]);
        break;
    case SYS_CONNECT:
        err = __sys_connect(a0, (struct sockaddr __user *)a1, a[2]);
        break;
    case SYS_LISTEN:
        err = __sys_listen(a0, a1);
        break;
    case SYS_ACCEPT:
        err = __sys_accept4(a0, (struct sockaddr __user *)a1,
                    (int __user *)a[2], 0);
        break;
    ...
    ...
    default:
        err = -EINVAL;
        break;
    
    return err;

 

 

 

TCP编程

 

创建SeverSocket的几种构造方法:

 

SeverSocket();   //创建不绑定服务器的套接字
ServerSocket server = new ServerSocket(int port);  //指定端口号绑定
ServerSocket(int port,int backlog);   //指定的backlog创建服务器套接字并绑定到指定的本地端口号
ServerSocket(int port,int backlog,InetAddress bindAddr);  //使用指定的端口,监听backlog和要绑定的本地IP地址创建服务器

 

 

Accept方法用于阻塞式等待客户端连接,等到一个连接后就返回一个客户端的Socket的对象实例。

 

Socket client = server.accept();

 

 

DataInputStream是用来获取输入流的相关信息的,返回一个DataInputStream对象的实例。

 

DataInputStream dis = new DataInputStream(client.getInputStream());

 

 

DataOutputStream用来操作输出流的相关信息,返回一个DataOutputStream对象实例。

 

DataOutputStream dos= new DataOutputStream(client.getOutputStream());

 

 

以下是一些方法:

 

方法摘要 
void bind(SocketAddress bindpoint) 将套接字绑定到本地地址。
void close() 关闭此套接字。
void connect(SocketAddress endpoint) 将此套接字连接到服务器。
void connect(SocketAddress endpoint, int timeout) 将此套接字连接到服务器,并指定一个超时值。
SocketChannel getChannel() 返回与此数据报套接字关联的唯一 SocketChannel 对象(如果有)。
InetAddress getInetAddress() 返回套接字连接的地址。
InputStream getInputStream() 返回此套接字的输入流。
boolean getKeepAlive() 测试是否启用 SO_KEEPALIVE。
InetAddress getLocalAddress() 获取套接字绑定的本地地址。
int getLocalPort() 返回此套接字绑定到的本地端口。
SocketAddress getLocalSocketAddress()返回此套接字绑定的端点的地址,如果尚未绑定则返回null`。
boolean getOOBInline() 测试是否启用 OOBINLINE。
OutputStream getOutputStream() 返回此套接字的输出流。
int getPort() 返回此套接字连接到的远程端口。
int getReceiveBufferSize()获取此Socket的 SO_RCVBUF 选项的值,该值是平台在Socket` 上输入时使用的缓冲区大小。
SocketAddress getRemoteSocketAddress()返回此套接字连接的端点的地址,如果未连接则返回null`。
boolean getReuseAddress() 测试是否启用 SO_REUSEADDR。
int getSendBufferSize()获取此Socket的 SO_SNDBUF 选项的值,该值是平台在Socket` 上输出时使用的缓冲区大小。
int getSoLinger() 返回 SO_LINGER 的设置。
int getSoTimeout() 返回 SO_TIMEOUT 的设置。
boolean getTcpNoDelay() 测试是否启用 TCP_NODELAY。
int getTrafficClass() 为从此 Socket 上发送的包获取 IP 头中的流量类别或服务类型。
boolean isBound() 返回套接字的绑定状态。
boolean isClosed() 返回套接字的关闭状态。
boolean isConnected() 返回套接字的连接状态。
boolean isInputShutdown() 返回是否关闭套接字连接的半读状态 (read-half)。
boolean isOutputShutdown() 返回是否关闭套接字连接的半写状态 (write-half)。
void sendUrgentData(int data) 在套接字上发送一个紧急数据字节。
void setKeepAlive(boolean on) 启用/禁用 SO_KEEPALIVE。
void setOOBInline(boolean on) 启用/禁用 OOBINLINE(TCP 紧急数据的接收者) 默认情况下,此选项是禁用的,即在套接字上接收的 TCP 紧急数据被静默丢弃。
void setPerformancePreferences(int connectionTime, int latency, int bandwidth)` 设置此套接字的性能偏好。
void setReceiveBufferSize(int size)将此Socket` 的 SO_RCVBUF 选项设置为指定的值。
void setReuseAddress(boolean on) 启用/禁用 SO_REUSEADDR 套接字选项。
void setSendBufferSize(int size)将此Socket` 的 SO_SNDBUF 选项设置为指定的值。
static void setSocketImplFactory(SocketImplFactory fac) 为应用程序设置客户端套接字实现工厂。
void setSoLinger(boolean on, int linger) 启用/禁用具有指定逗留时间(以秒为单位)的 SO_LINGER。
void setSoTimeout(int timeout) 启用/禁用带有指定超时值的 SO_TIMEOUT,以毫秒为单位。
void setTcpNoDelay(boolean on) 启用/禁用 TCP_NODELAY(启用/禁用 Nagle 算法)。
void setTrafficClass(int tc) 为从此 Socket 上发送的包在 IP 头中设置流量类别 (traffic class) 或服务类型八位组 (type-of-service octet)。
void shutdownInput() 此套接字的输入流置于“流的末尾”。
void shutdownOutput() 禁用此套接字的输出流。
String toString()将此套接字转换为String。

 

 

 

版本一:一个服务器和一个客户端通信

 

server.java

 

package chat1;
​
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
​
/*
 * 简易在线聊天程序服务端
 */
public class server 
    public static void main(String[]args) throws UnknownHostException,IOException
        System.out.println("---server---");
        //指定端口 使用ServerSocket创建服务器
        ServerSocket server = new ServerSocket(666);
        //阻塞式等待连接
        Socket client = server.accept();
        System.out.println("一个客户端连接建立");
        //接收消息
        DataInputStream dis = new DataInputStream(client.getInputStream());
        String msg = dis.readUTF();
        System.out.println("client say:"+msg);
        //返回消息
        DataOutputStream dos= new DataOutputStream(client.getOutputStream());
        dos.writeUTF(msg);
        //释放资源
        dos.flush();
        dos.close();
        dis.close();
        client.close();
    

 

 

package chat1;
​
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;
​
/*
 * 简易在线聊天程序客户端
 */
public class client 
    public static void main(String[]args) throws UnknownHostException, IOException
        System.out.println("---client---");
        //连接建立,使用Socket创建客户端,这里要注意端口号要跟本地其它已经写过的网络程序相区分开
        Socket client =new Socket("localhost",666);
        //客户端发送消息
        BufferedReader console=new BufferedReader(new InputStreamReader(System.in));
        String msg = console.readLine();
        DataOutputStream dos= new DataOutputStream(client.getOutputStream());
        dos.writeUTF(msg);
        dos.flush();
        //接收消息
        DataInputStream dis = new DataInputStream(client.getInputStream());
        msg = dis.readUTF();
        System.out.println(msg);
        //释放资源
        dos.close();
        dis.close();
        client.close();
        

 

 

这里只有一个客户端和一个服务端通信,也比较简单,就是服务端把客户端发来的消息再返回给客户端。我们来看一下运行结果吧。

 

 

版本二:一个服务器和多个客户端通信

 

Multiserver.java

 

package chat2;
​
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
​
/*
 * 简易在线聊天程序服务器端,实现多个客户消息发送
 */
public class Multiserver 
    public static void main(String[] args)throws IOException
        System.out.println("----server---");
        //指定端口666,使用SeverSocekt创建服务器
        ServerSocket server =new ServerSocket(666);
        //阻塞式监听,等待连接
        while(true)
            Socket client=server.accept();
            System.out.println("一个客户端连接建立");
            new Thread(new Channel(client)).start();
        
    
    //为了多个响应多个客户,封装成多线程
    static class Channel implements Runnable
        private Socket client;
        //输入输出流封装
        private DataInputStream dis;
        private DataOutputStream dos;
        private boolean isRuning;
        //构造器
        public Channel(Socket client) throws IOException
            this.client=client;
            try 
                //输入流
                dis = new DataInputStream(client.getInputStream());
                //输出流
                dos = new DataOutputStream(client.getOutputStream());
                isRuning = true;
             catch (IOException e) 
                // TODO Auto-generated catch block
                e.printStackTrace();
                release();
            
        
        //接收数据
        private String receive() 
            String msg = "";
            try 
                msg = dis.readUTF();
             catch (IOException e) 
                e.printStackTrace();
            
            return msg;
        
        //发送数据
        private void send(String msg) 
            System.out.println(msg);
            try 
                dos.writeUTF(msg);
                dos.flush();
             catch (IOException e) 
                e.printStackTrace();
            
            
        
        //释放资源
        private void release() throws IOException
            this.isRuning=false;
            Util.close(dis,dos);
            client.close();
        
        @Override
        public void run() 
            while(isRuning)
                String msg = receive();
                if(!msg.equals(""))
                    send(msg);
                
            
        
    

 

 

Multiclient.java

 

package chat2;
​
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;
​
/*
 * 简易在线聊天程序客户端,实现多个客户消息发送
 */
public class Multiclient 
    public static void main(String[]args) throws UnknownHostException, IOException
        System.out.println("---client---");
        //连接建立,使用Socket创建客户端,这里要注意端口号要跟本地其它已经写过的网络程序相区分开
        Socket client =new Socket("localhost",666);
        //发送消息
        new Thread(new send(client)).start();
        //接收消息
        new Thread(new receive(client)).start();
        

 

 

receive.java

 

package chat2;
​
import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;
​
/*
 * 使用多线程封装接收端
 */
public class receive implements Runnable
    private DataInputStream dis;
    private Socket client;
    private boolean isRuning = true;
    public receive(Socket client)
        this.client = client;
        try 
            dis = new DataInputStream(client.getInputStream());
         catch (IOException e) 
            e.printStackTrace();
            this.release();
        
    
    @Override
    public void run() 
        while(isRuning)
            String msg = receive();
            if(!msg.equals(""))
                //System.out.println(msg);
            
        
    
    //接收数据
    private String receive() 
        String msg = "";
        try 
            msg = dis.readUTF();
         catch (IOException e) 
            e.printStackTrace();
        
        return msg;
    
    //释放资源
    private void release()
        this.isRuning = false;
        Util.close(dis);
        try 
            client.close();
         catch (IOException e) 
            e.printStackTrace();
        
    

 

 

send.java

 

package chat2;
​
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
​
/*
 * 使用多线程封装发送端
 */
public class send implements Runnable
    private BufferedReader console;
    private DataOutputStream dos;
    private Socket client;
    private boolean isRuning = true;
    //构造器
    public send(Socket client)
        this.client = client;
        console = new BufferedReader(new InputStreamReader(System.in));
        try 
            dos= new DataOutputStream(client.getOutputStream());
         catch (IOException e) 
            e.printStackTrace();
            this.release();
        
    
    @Override
    public void run() 
        while(isRuning)
            String msg = getStrFromConsole();
            if(!msg.equals(""))
                send(msg);
            
        
        
    
    //从控制台获取消息
    private String getStrFromConsole()
        try 
            return console.readLine();
         catch (IOException e) 
            e.printStackTrace();
        
        return "";
    
    //发送消息
    private void send(String msg)
        System.out.println(msg);
        try 
            dos.writeUTF(msg);
            dos.flush();
         catch (IOException e) 
            e.printStackTrace();
        
    
    //释放资源
    private void release()
        this.isRuning = false;
        Util.close(dos);
        try 
            client.close();
         catch (IOException e) 
            e.printStackTrace();
        
    

 

 

Util.java

 

package chat2;
​
import java.io.Closeable;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;
​
/*
 * 工具类
 */
public class Util 
    /*
     * 释放资源
     */
    public static void close(Closeable...targets)
        for(Closeable target:targets)
            try
                if(null!=target)
                    target.close();
            catch(Exception e)
                
            
        
    

 

 

这里服务器是阻塞式监听多个客户端的,为了响应多个客户,封装成了多线程。每个客户端来请求服务的时候都是一个channel,而服务器在和一个客户端建立连接后又可以和其它的客户端建立连接。把具体的响应过程全部写到了run()方法中。封装了一个单独的工具类Util用于释放资源。把接收消息和发送消息单独封装成一个类,方便使用。且有利于代码的维护和重写。我们来看看运行结果吧:

 

 

本来还有一个版本三,实现了群聊,但是有一点小bug,这里就不展示了。作为一个java小白,好不容易写出来的。

 

 

 

基于java实现hello/hi简单网络聊天程序

目录Socket简要阐述Socket的概念Socket原理hello/hi的简单网络聊天程序实现服务器端客户端程序执行结果跟踪分析调用栈&LinuxAPI对比创建ServerSocket调用栈图示源码分析Socket绑定调用栈图示源码分析Socket监听调用栈图示源码分析Socket... 查看详情

使用java实现一个hello/hi的简单的网络聊天程序(代码片段)

1、socket原理    Socket实质上提供了进程通信的端点。进程通信之前,双方首先必须各自创建一个端点,否则是没有办法建立联系并相互通信的。正如打电话之前,双方必须各自拥有一台电话机一样。     &n... 查看详情

使用python完成一个hello/hi的简单的网络聊天程序(代码片段)

...在这篇文章中,我将先简要介绍socket原理,然后给出一个利用Python实现的简单通信样例,最后通过跟踪系统调用来分析Python中socket函数与Linux系统调用的对应关系。1.socket简介Socket是应用层与TCP/IP协议族通信的中间软件抽象层,... 查看详情

c语言实现一个hello/hi的简单聊天程序并跟踪分析到系统调用(代码片段)

socket编程介绍Socket接口是TCP/IP网络的API,Socket接口定义了许多函数或例程,可以用它们来开发TCP/IP网络上的应用程序。Socket接口设计者最先是将接口放在Unix操作系统里面的。如果了解Unix系统的输入和输出的话,就很容易了解Sock... 查看详情

java利用tcp编程实现简单聊天室

...、可靠的、基于字节流的传输层通信协议,在Java中我们利用ServerSocket类来建立服务端,利用Socket类来建立客户端。这里要注意,在TCP中,Socket实际上是指Ser 查看详情

一个hello/hi的简单的网络聊天程序(代码片段)

...器端代码,源代码部分如下图所示:服务器端代码1importsocket23HOST=‘127.0.0.1‘4PORT=888856server=socket.socket()7server.bind((HOST,PORT))8server.listen(1)910print(f‘theserve 查看详情

一个简单的javaweb服务器实现

... 一个简单的Javaweb服务器实现,比较简单,基于java.net.Socket和java.net.ServerSocket实现;程序执行步骤创建一个ServerSocket对象;调用ServerSocket对象的accept方法,等待连接,连接成功会返回一个Socket对象,否则一直阻塞等待;从Socket... 查看详情

java中socket实现最简单的客户端与服务端通信

Java中Socket实现最简单的客户端与服务端通信引言:因为最近项目中要接入某通信协议接口,基于TCP/IP的socket接口。于是就在本地弄一个最简单的Socket通信仅供学习。话不多说,直接开摆客户端代码packagetest;importjava.io.*;importjava.ne... 查看详情

hello/hi的简单的网络聊天程序(代码片段)

...议和端口号可以唯一标示主机的一个进程,这样我们可以利用ip地址+协议+端口号唯一标示网络中的一个进程。 二、socket通信  能够唯一标示网络中的进程后,它们就可以利用socket进行通 查看详情

基于《仙剑奇侠传柔情版》利用java的简单实现

基于《仙剑奇侠传柔情版》利用Java的简单实现(一)2018-12-01 23:55:36 byLouis 一,新建一个类GameFrame.class,具体代码如下:packagefirstDemo;importjavax.swing.JFrame;/***本类文件表示游戏案例的窗口类,也就是运行之后会呈现出一... 查看详情

一个简单的hello/hi的网络聊天程序(代码片段)

TCP套接字函数了解socket函数为了执行网络I/O,一个进程必须做的第一件事情就是调用socket函数,指定期望的通信协议类型(使用ipv4的TCP、使用ipv6的UDP、Unix域字节流协议等)#include<sys/socket.h>intsocket(intfamily,inttype,intprotocol);返... 查看详情

java中socket实现最简单的客户端与服务端通信(代码片段)

Java中Socket实现最简单的客户端与服务端通信引言:因为最近项目中要接入某通信协议接口,基于TCP/IP的socket接口。于是就在本地弄一个最简单的Socket通信仅供学习。话不多说,直接开摆客户端代码packagetest;importjava.io.*;importjava.ne... 查看详情

java代码实现socket接口通讯(堵塞i/o)

  传统的java实现socket通讯比较简单实现,不过它属于堵塞式的I/O流存取,只能由一个线程完成当前任务才能起下个一个线程,无法解决高并发; 1、简单的socketservice对每一个Socket连接建立一个Handler处理线程,处理线... 查看详情

java实现一个最简单的tomcat服务(代码片段)

...;类中的; 2.如何建立连接? 要通讯,必须要建议socket连接,我们需要使用哪种socket,是根据它使用的哪种协议进行判断的。tcp协议orudp协议?http协议本身属于tcp协议,因此我们选择的socket是基本tcp协议的soc 查看详情

基于python完成一个hello/hi的简单的网络聊天程序(代码片段)

一、Socket套接字简介套接字(socket)是一个抽象层,应用程序可以通过它发送或接收数据,可对其进行像对文件一样的打开、读写和关闭等操作。套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信。网... 查看详情

java实现简单的socket通信

  今天学习了一下java如何实现socket通信,感觉难点反而是在io上,因为java对socket封装已经很完善了。  今天代码花了整个晚上调试,主要原因是io的flush问题和命令行下如何运行具有package的类,不过最后问题基本都解决了,... 查看详情

如何创建一个socket并进行通信

...双向通讯的一端,它既可以接受请求,也可以发送请求,利用它可以较为方便的编写网络上的数据的传递。在java中,有专门的socket类来处理用户的请求和响应。利用SOCKET类的方法,就可以实现两台计算机之间的通讯。这里就介... 查看详情

java利用反射实现注解简单功能

//自定义一个简单的注解@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD,ElementType.PARAMETER,ElementType.LOCAL_VARIABLE})public@interfaceDougest{Stringvalue()def 查看详情