简易命令行界面的C/S聊天室


最近几天复习了下java网络编程socket使用我觉得虽然下面的内容很基础但是如果想要做出个好的东西想要快速掌握以后要学习的先要把基础打牢

如果基础打得好那么将来学习新的知识会很快,其实都是同理的。

如果大神能发挥下,拓展下完善下功能那就更好了,请在下面留下您的想法我会一直维护我的这些文章。

TCP 协议基础

IP协议是Internet的使用的一个关键协议,全称是Internet Protocol,即Internet协议通常简称IP协议通过IP协议,从而使Internet成为一个允许连接不同类型计算机的不同操作系统的网络。如果想要两台计算机通信那么就要使用相同的语言 那么就是用IP协议但是只保证计算机能发送接受分组数据,IP协议负责将消息从一个主机发送到另一个主机,消息在传送过程中被分割成包。但是这样只是解决了他们之间的发送和接收数据但是还不能解决数据分组在数据传输过程中出现的问题。所以就需要使用TCP协议以保证提供可靠并且无差错的通信服务。

TCP协议是面向连接的端对端的协议。这是因为他对两台计算机之间的链接起到了重要的作用建立的链接用于发送和接收数据的虚拟链路

TCP和IP协议的功能虽然不尽相同,也可以分开使用,但是他们是在同一时期作为一个协议来设计的,并且在功能上也是互补的。只有两者结合起来才能保证internet在复杂的环境下正常的运行凡事要连接到internet的计算机都必须同时安装和使用这两个协议因此唱吧这两个协议叫做TCP/IP协议

使用serverSocket创建TCP服务器端

在两个通信实体之间没有建立虚拟链路之前必须先有一个通信实体先做出“主动姿态”主动地接受来自其他实体的连接请求。Java中接收其他的通信实体连接请求的类是ServerSocket,serverSocket用于监听来自socket端的连接,如果没有连接,他将一直处于等待状态,serverSocket包含一个监听来自客户端请求的方法

Socket accept():如果接收到一个客户端的Socket的链接的请求,该方法返回一个与客户端对应的socket否则该方法一直处于等待状态线程也被阻塞

为了创建serversocket对像,提供了如下几个构造器

serverSocket(int port)指定的端口创建一个serverSocket对像该端口应该有一个有效的端口整数

serverSocket(int port,int backlog):增加一个用来改变连接队列长度的参数backlog

当serverSocket使用完毕后,应使用serverSocket的close()方法关闭该serverSocket。在通常情况下

 

服务器不用改制接受一个客户端的请求,而应该不断地接受来自客户端的所有的请求,所以java程序通常会循环的不断的调用serverSocket的accept()方法

使用socket进行通信

客户端通常可以使用socket的构造器连接到指定的服务器,socket通常可以使用给定的两个构造器连接到相应的主机或者是相应的IP地址的服务器这样就能实现对话

--

加入多线程

前面的Server和Client只是进行了简单的通信操作:服务器端接收到客户端的连接之后,服务器端向客户端输出了一个字符串,而客户但也只是读取服务器端的字符串后就退出了,实际应用中的客户端可能根据需要和服务器端保持长时间通信,即服务器端需要不断的读取客户端数据,并向客户端写入数据;客户端也需要不断的读取服务器端的数据,并向服务器端写入数据。

在使用传统的BufferReader的readLine()方法读取数据时,在该方法成功返回之前,线程被阻塞,程序无法执行。考虑到这个因素,服务器端应该为每个Socket启动一个线程,每个线程负责与一个客户端进行通信

客户端读取服务器端数据的县城同样会被阻塞,所以系统应该单独启动一个线程。该线程专门负责读取服务器端的数据。

现在考虑实现一个命令行的界面的C/S聊天室应用,服务器端应该包含多个线程,每个Socket对应一个线程,该线程负责读取Socket对应输入流的数据。并将读取到的数据向每个Socket输出流发送一次(将一个客户端的数据广播给其他客户端)需要在服务器端使用list保存所有的Socket

服务器端的实现:

<span style="font-size:18px;"><span style="font-size:18px;">package com.example.administrator.openinternet;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

/**
 * Created by Administrator on 2015/7/23.
 * 服务器端的程序
 */
public class javaSocket {
    public static List<Socket> socketList = Collections.synchronizedList(new ArrayList<Socket>());
    public static void main (String [] args) throws IOException {
        ServerSocket ss = new ServerSocket(30000);
        while(true)
        {
            Socket s = ss.accept();
            socketList.add(s);
            new Thread( new ServerThread(s)).start();
        }
    }
}
</span></span>

服务器端的线程类:

<span style="font-size:18px;"><span style="font-size:18px;">package com.example.administrator.openinternet;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.net.SocketException;

/**
 * Created by Administrator on 2015/7/23.
 * 服务器端的线程
 */
public class ServerThread implements Runnable {
    Socket s = null;
    BufferedReader br = null;
    public ServerThread(Socket s){
        this.s = s ;
        try {
            br = new BufferedReader(new InputStreamReader(s.getInputStream()));//创建并读取流
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * Starts executing the active part of the class' code. This method is
     * called when a thread is started that has been created with a class which
     * implements {@code Runnable}.
     */
    @Override
    public void run()
    {
        try
        {
            String content = null;
            while ((content = readFromClient())!=null)
            {
                for(Socket s:javaSocket.socketList)
                {
                    PrintStream ps = new PrintStream(s.getOutputStream());
                }
            }

        }catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    private String readFromClient() {
        try
        {
            return br.readLine();

        }catch (IOException e) {
            e.printStackTrace();
            javaSocket.socketList.remove(s);//移除socketList中的数据三
        }
        return null;
    }
}
</span></span>
客户端实现:

<span style="font-size:18px;">package com.example.administrator.openinternet;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;

/**
 * Created by Administrator on 2015/7/23.
 * 我的客户端的程序
 */
public class MyClient {
    public static void main(String [] args) throws IOException
    {
        Socket s = new Socket("127.0.0.1",30000);
        new Thread( new ClientThread(s)).start();
        PrintStream ps = new PrintStream(s.getOutputStream());
        String line = null;
        BufferedReader br = new BufferedReader( new InputStreamReader(System.in));
        while ((line = br.readLine())!=null)
        {
            ps.println(line);
        }
    }
}
</span>

客户端线程:

<span style="font-size:18px;">package com.example.administrator.openinternet;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;

/**
 * Created by Administrator on 2015/7/23.
 * 客户端的线程
 */
public class ClientThread implements Runnable {
    private  Socket s ;
    BufferedReader br = null;

    public ClientThread(Socket s) throws IOException {
        this.s = s ;
        br = new BufferedReader(new InputStreamReader(s.getInputStream()));

    }

    /**
     * Starts executing the active part of the class' code. This method is
     * called when a thread is started that has been created with a class which
     * implements {@code Runnable}.
     */
    @Override
    public void run()
    {
        try
        {
            String content = null;
            while ((content = br.readLine())!=null)
            {
                System.out.println(content);
            }
        }catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}
</span>

这就实现了简单的回话,其实可以继续扩展比如实现客户端和服务器端的数据的传递过几天更新过来


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值