最近研究了一下Java中的socket通信机制,由于英语水平不好,只能习惯性的百度、谷歌上找相关类文章,总是有一些收获的,也遇到了不少小困难(其实是对这些机制不了解),现在写下来。
顺便说一下,网上的那些源代码都是复制来复制去,照样写上去总是不能正常运行,是他们的错的还是我写的是错的?
下面是一些最基本的东西,网上总结的。
端口 :端口是将应用程序与IP网络相关联,是应用进程的地址标识。分为两种公用端口(0~1023)和临时端口(1024~65535),我们用的就是临时端口。
套接字:区分不同应用程序进程间的网络通信和连接,主要有3个参数:通信的目的IP地址、使用的传输层协议(TCP或UDP)和使用的端口号。Socket原意是“插座”。通过将这3个参数结合起来,与一个“插座”Socket绑定,应用层就可以和传输层通过套接字接口,区分来自不同应用程序进程或网络连接的通信,实现数据传输的并发服务。
流:Java中的流分为两种,一种是字节流(8位),另一种是字符流(16),分别由四个抽象类来表示:InputStream,OutputStream,Reader,Writer。
InputStream/OutputStream:
是所有的输入和输入类的基类。
面向字节形式的I/O操作(8位字节流)。
Reader/Writer:
面向字符的I/O操作(16位的Unicode字符,在JAVA语言中,byte类型是8位的,char类型是16位的,所以在处理中文的时候需要用Reader和Writer)
InputStreamReader:可以将InputStream转换为Reader
OutputStreamWriter:可以将OutputStream转换为Writer
关于TCP的三次握手可以看这个:http://www.cnblogs.com/rootq/articles/1377355.html
基于TCP的聊天室
下面是效果图:
客户端将消息发往服务端用的是字节流,服务器端发往客户端用的是字符流。
Client客户端代码:
开启一个ServerSocket监听一个端口
/** * 服务器端 * */ public class Server { private ServerSocket sock ; private String str ; private List<Socket> sockLi = new ArrayList<Socket>(); private String conte = null;//当前接收到的信息 public Server() { try { //* 创建ServerSocket负责接收客户连接请求 sock = new ServerSocket(5171,3); } catch (IOException e) { e.printStackTrace(); } } public void beginServer() { while(true) { try { Socket soc = sock.accept() ; sockLi.add(soc); //开启线程 new Thread(new Serv(soc)).start(); } catch (IOException e) { e.printStackTrace(); } } } private class Serv implements Runnable{ private Socket soc ; public Serv(Socket so) { this.soc = so; } @Override public void run() { try { InputStream instr = soc.getInputStream(); while(!soc.isClosed()){ //从流中读取下一个字节 int len = instr.read(); //从字节流中读取信息 byte[] bt = new byte[len]; instr.read(bt, 0, len); str = new String(bt); if(str.equals("end")) { Thread.sleep(200); soc.close(); sockLi.remove(soc); break ; } else if(str.trim().equals("")) { continue ; } else { conte = str; sendMessage(); } } } catch (IOException e) { //连接断开 sockLi.remove(soc); e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } } private void sendMessage() { PrintWriter pr; for(Socket so:sockLi) { try { pr = new PrintWriter(so.getOutputStream(),true); pr.print(conte+"\n"); pr.flush(); } catch (IOException e) { e.printStackTrace(); } } } public static void main(String[] args) { Server se = new Server(); se.beginServer(); } }提一下 readline和read都会阻塞进程,readline遇到\n会返回,所以在客户端发送消息后要发送一个\n表示已经发送完。 客户端:具体操作类ScoketSend
public class SocketSend { public static void main(String[] args) { } private Handler hd ; private BufferedReader buf ; static Socket sock ; private Bundle bun; private String name ; public SocketSend(Handler hd,String name) { this.name = name ; this.hd = hd ; try { sock = new Socket(); bun = new Bundle(); //android中的本地地址为10.0.2.2 InetSocketAddress isa = new InetSocketAddress("10.0.2.2", 5171); sock.connect(isa, 300);//如果300ms没有连接到就会失败 buf = new BufferedReader( new InputStreamReader(sock.getInputStream())); new Thread(new messtake(buf)).start(); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } private class messtake implements Runnable{ private BufferedReader bu= null ; public messtake(BufferedReader buf) { bu = buf ; } @Override public void run() { String msg =""; try { while ((msg = bu.readLine()) != null) { if(msg.trim().equals("")) {//这里会接收到一个空白字符串,还不知道为什么 ! continue; } //先把字符串中原本的/n替换掉,客户端接收再替换过来 //一下是android部分通知ui更新 bun.putString("contentMess", msg.replace("Sun948040237", "\n")); bun.putInt("type", 1); Message message = new Message(); message.setData(bun); hd.sendMessage(message); } } catch (IOException e) { e.printStackTrace(); } } } //向服务器发送消息 public void send(String content) { try { content = name+"&#&" +content ; OutputStream ou = sock.getOutputStream(); ou.write(content.getBytes().length); ou.write(content.getBytes()); ou.flush(); } catch (IOException e) { bun.putString("contentMess", "发送失败:"+content); bun.putInt("type", 0); Message message = new Message(); message.setData(bun); hd.sendMessage(message); e.printStackTrace(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
客户端调用的时候
//NAME是昵称
String con = "苹果"; new SocketSend(myHandler,NAME).send(con.replace("\n", "Sun948040237")+"\n");
下面是下载示例的链接