端口号可以从0~65535:

今天就写TCP相关。在下一节我会分别写有关UDP,还有MultiCastSocket。

Socket的工作原理:

通信两端都建立一个Socket,从而两端形成虚拟链路。通过IO流完成网络通信。

实现两台终端进行通信需使用IP地址与port。

InetAddress:可获取IP地址 & 主机名的类

实例:

import java.io.IOException;
import java.net.InetAddress; public class InetAnddressTest {
public static void main(String[] args) throws IOException {
InetAddress ip = InetAddress.getByName("www.baidu.com");
System.out.println(ip.getHostAddress());
System.out.println(ip.getHostName());
System.out.println("isReachable:"+ip.isReachable(5000)); InetAddress ip2 = InetAddress.getLocalHost();
System.out.println(ip2.getHostAddress());
System.out.println(ip2.getHostName());
System.out.println("isReachable:"+ip2.isReachable(5000));
}
}

先了解TCP

当一个通信实体发送一个消息给另一个通信实体后,需要收到另一个通信实体的确认信息(握手)。如果没有收到,则会再次发送刚才发送的信息。建立虚拟链路之前必须有一个主动接受来自其他通信实体的连接请求。即ServerSocket。

ServerSocket(上图右边的)【服务端】:

ServerSocket(int port):用端口来创建一个ServerSocket,此时localAddress为默认为服务ip。如果有终端有多个ip(多网卡)时可以用带ip参数的构造方法。

accept():等待接受Socket的连接请求,返回一个发送连接请求的客户端socket对象。

getInputStream()/ getOuptStream():获取输入输出流来完成读写操作。

Socket(上图左边的)【客户端】:

Socket(InetAddress/String remoteAddress,int port):指定服务器的ip地址,端口号。

  *如果new了一个客户端Socket将会连接到服务端。即accept方法返回socket。

getInputStream()/ getOuptStream():获取输入输出流来完成读写操作。

SetTimeOut(int timeout):当超出限定时间会抛出SocketTimeoutException异常。

  *s.connconnect(new InetAddress(host,port),1000):连接中可以设定连接超时。

实例:

服务端代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List; public class Server { public static List<Socket> clients = new ArrayList<Socket>(); public static void main(String[] args) {
int port = 1025;
try {
ServerSocket serverSocket = new ServerSocket(port);
while (true) {
Socket client = serverSocket.accept();
clients.add(client);
new Thread(new Client(client)).start();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} } public static class Client implements Runnable {
Socket client;
BufferedReader br; public Client(Socket client) throws IOException {
this.client = client;
br = new BufferedReader(new InputStreamReader(
client.getInputStream()));
} public String read() {
try {
return br.readLine();
} catch (IOException e) {
// TODO Auto-generated catch block
clients.remove(client);
}
return null; } public void run() {
// TODO Auto-generated method stub
try { String msg = null;
while ((msg = read()) != null) {
for (Socket s : clients) {
PrintStream pw = new PrintStream(s.getOutputStream());
pw.println(msg);
System.out.println(msg);
}
}
br.close();
} catch (IOException e) {
// TODO Auto-generated catch block
} }
} }

客户端代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.Socket; public class Client{ /**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException { String ip = InetAddress.getLocalHost().getHostAddress();
int port = 1025;
Socket socket = new Socket(ip, port);
new Thread(new ClientReceiver(socket)).start(); PrintStream pw = new PrintStream(socket.getOutputStream());
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String msg = null;
while ((msg = br.readLine()) != null) {
pw.println(msg);
}
} public static class ClientReceiver implements Runnable {
Socket client;
BufferedReader br; public ClientReceiver(Socket client) throws IOException {
this.client = client;
br = new BufferedReader(new InputStreamReader(
client.getInputStream()));
} public void run() {
// TODO Auto-generated method stub
try {
String msg = null;
while ((msg = br.readLine()) != null) {
System.out.println(msg);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

运行:

  1. 先运行Server再运行Client
  2. 在Client中输入你要传送的文字。

以上是堵塞式网络通信,所以需要创建线程去完成。非堵塞式NIO可以让服务器使用一个或有限几个线程来同时处理连接到服务器上的所有客户端。

通道Socket:

在NIO涉及到几个重要的:Channel(通道),Buffer(缓冲区),Selector(选择器)。

NIO是双向的,需要Channel来完成读写操作,然而Channel是由Selector来管理。 读取或写入的,为了高效操做读写用到Buffer。

通过SocketChannel,以TCP来向网络连接的两端读写数据;

通过ServerSocketChanel能够监听客户端发起的TCP连接,并为每个TCP连接创建一个新的SocketChannel来进行数据读写;

通过DatagramChannel,以UDP协议来向网络连接的两端读写数据。

实例:

服务端代码:

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator; public class MyNioServer { protected Selector selector;
static int BufferSize = 2 * 1024;
protected ByteBuffer clientBuffer = ByteBuffer.allocate(BufferSize);
ServerSocketChannel server; public MyNioServer(int port) throws IOException {
selector = this.getSelector(port); } // 获取Selector
protected Selector getSelector(int port) throws IOException {
Selector sel = Selector.open();
server = ServerSocketChannel.open();
server.socket().bind(new InetSocketAddress("localhost", port));
server.configureBlocking(false);
server.register(sel, SelectionKey.OP_ACCEPT);
return sel;
} // 监听端口
public void listen() {
try {
/*
* 我们调用 Selector 的 select() 方法。这个方法会阻塞,直到至少有一个已注册的事件发生。
* 当一个或者更多的事件发生时, select() 方法将返回所发生的事件的数量。该方法必须首先执行。
*/
while (selector.select() > 0) {
Iterator iter = selector.selectedKeys().iterator();
while (iter.hasNext()) {
/*
* 在处理 SelectionKey 之后,我们必须首先将处理过的SelectionKey 从选定的键集合中删除。
* 如果我们没有删除处理过的键,那么它仍然会在主集合中以一个激活的键出现,这会导致我们尝试再次处理它。
* 我们调用迭代器的 remove() 方法来删除处理过的 SelectionKey:iter.remove();
*/
SelectionKey key = (SelectionKey) iter.next();
iter.remove();
process(key);
}
}
} catch (IOException e) {
e.printStackTrace();
}
} // 处理事件
protected void process(SelectionKey key) throws IOException {
if (key.isAcceptable()) { // 接收请求
SocketChannel channel = server.accept();
// 设置非阻塞模式
channel.configureBlocking(false);
//注册读动作
channel.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) { // 读信息
SocketChannel channel = (SocketChannel) key.channel();
if (channel.read(clientBuffer) > 0) {
// 重设此缓冲区,将限制设置为当前位置,然后将当前位置设置为0
clientBuffer.flip();
byte[] data = clientBuffer.array();
System.out.println(new String(data).trim());
clientBuffer.clear();
}
//注册写动作
SelectionKey sKey = channel.register(selector,SelectionKey.OP_WRITE);
//传递写对应的附件(值)
sKey.attach("hello! i am server!");
} else if (key.isWritable()) { // 写信息
SocketChannel channel = (SocketChannel) key.channel();
String name = (String) key.attachment();
clientBuffer.put(name.getBytes());
clientBuffer.flip();
channel.write(clientBuffer);
clientBuffer.clear();
// 不加close会无限循环
channel.close();
} } public static void main(String[] args) {
int port = 8888;
try {
MyNioServer server = new MyNioServer(port);
server.listen();
} catch (IOException e) {
e.printStackTrace();
}
}
}

客户端代码:

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator; public class MyNioClient { static InetSocketAddress ip = new InetSocketAddress("localhost", 8888); static class Message implements Runnable {
String msg = ""; public Message(String msg) {
this.msg = msg;
} public void run() {
try {
// 打开Socket通道
SocketChannel client = SocketChannel.open();
// 打开选择器
Selector selector = Selector.open();
// 设置为非阻塞模式
client.configureBlocking(false);
// 注册连接服务端socket动作
client.register(selector, SelectionKey.OP_CONNECT);
// 连接
client.connect(ip);
// 分配内存
ByteBuffer buffer = ByteBuffer.allocate(8 * 1024);
while (selector.select() > 0) {
Iterator iter = selector.selectedKeys().iterator();
while (iter.hasNext()) {
SelectionKey key = (SelectionKey) iter.next();
iter.remove();
if (key.isConnectable()) {
SocketChannel channel = (SocketChannel) key
.channel();
if (channel.isConnectionPending())
channel.finishConnect();
buffer.put(msg.getBytes());
buffer.flip();
channel.write(buffer);
buffer.clear();
key.interestOps(SelectionKey.OP_READ);
} else if (key.isReadable()) {
SocketChannel channel = (SocketChannel) key
.channel();
buffer.clear();
int count = channel.read(buffer);
if (count > 0) {
buffer.flip();
msg = "";
while (buffer.remaining() > 0) {
byte b = buffer.get();
msg += (char) b; }
System.out.println(msg);
buffer.clear();
} else {
client.close();
break;
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
} public static void main(String[] args) throws IOException {
new Thread(new Message("hello! i am client!")).start();
}
}

运行:

  1. 先运行Server再运行Client

Socket(1)的更多相关文章

  1. socket读写返回值的处理

    在调用socket读写函数read(),write()时,都会有返回值.如果没有正确处理返回值,就可能引入一些问题 总结了以下几点 1当read()或者write()函数返回值大于0时,表示实际从缓冲 ...

  2. Socket聊天程序——Common

    写在前面: 上一篇记录了Socket聊天程序的客户端设计,为了记录的完整性,这里还是将Socket聊天的最后一个模块--Common模块记录一下.Common的设计如下: 功能说明: Common模块 ...

  3. Socket聊天程序——客户端

    写在前面: 上周末抽点时间把自己写的一个简单Socket聊天程序的初始设计和服务端细化设计记录了一下,周二终于等来毕业前考的软考证书,然后接下来就是在加班的日子度过了,今天正好周五,打算把客户端的详细 ...

  4. Socket聊天程序——服务端

    写在前面: 昨天在博客记录自己抽空写的一个Socket聊天程序的初始设计,那是这个程序的整体设计,为了完整性,今天把服务端的设计细化记录一下,首页贴出Socket聊天程序的服务端大体设计图,如下图: ...

  5. Socket聊天程序——初始设计

    写在前面: 可能是临近期末了,各种课程设计接踵而来,最近在csdn上看到2个一样问答(问题A,问题B),那就是编写一个基于socket的聊天程序,正好最近刚用socket做了一些事,出于兴趣,自己抽了 ...

  6. Java中的Socket的用法

                                   Java中的Socket的用法 Java中的Socket分为普通的Socket和NioSocket. 普通Socket的用法 Java中的 ...

  7. Android Socket连接PC出错问题及解决

    最近测试问题:Android 通过Socket链接电脑,ip和端口都是正确的,也在同一网段,可android端就是报异常如下: 解决办法:测试电脑的防火墙可能开着,在控制面板把防火墙打开即可.

  8. Linux下的C Socket编程 -- server端的继续研究

    Linux下的C Socket编程(四) 延长server的生命周期 在前面的一个个例子中,server在处理完一个连接后便会立即结束掉自己,然而这种server并不科学啊,server应该是能够一直 ...

  9. Mono 3.2.3 Socket功能迎来一稳定的版本

    由于兴趣自己业余时间一直在搞.net下面的通讯应用,mono的存在得以让.NET程序轻松运行在Linux之下.不过经过多尝试Socket相关功能在Mono下的表现并不理想.不管性能还是吞吐能力方面离我 ...

  10. Demo源码放送:打通B/S与C/S !让HTML5 WebSocket与.NET Socket公用同一个服务端!

    随着HTML5 WebSocket技术的日益成熟与普及,我们可以借助WebSocket来更加方便地打通BS与CS -- 因为B/S中的WebSocket可以直接连接到C/S的服务端,并进行双向通信.如 ...

随机推荐

  1. conpot_usage简要说明

    conpot是一个ICS(工业控制系统)蜜罐, 旨在收集攻击者针对工业控制系统的攻击方法和动机. 这篇文章主要用来说明conpot的用户定制相关的一些配置. (英文原文详见: https://gith ...

  2. Flex4/Flash多文件上传(带进度条)实例分享

    要求 必备知识 本文要求基本了解 Adobe Flex编程知识和JAVA基础知识. 开发环境 MyEclipse10/Flash Builder4.6/Flash Player11及以上 演示地址 演 ...

  3. dell N1500 安全配置

    http://www.dell.com/Support/Article/us/en/19/HOW10832 Setting a management IP address A reachable IP ...

  4. WWF3事件类型活动<第三篇>

    WWF将工作流分为两大类: 面向Human:在工作流运行时通过用户对外部应用程序的操作来影响工作流的业务流转. 面向System:应用程序控制流程. 工作流与应用程序都是可以单独存在的,因此它们之间的 ...

  5. 【MySQL】删除大表的讨论【转】

    转自http://tech.ddvip.com/2013-07/1373269453198566.html 微博上讨论MySQL在删除大表engine=innodb(30G+)时,如何减少MySQL ...

  6. ios开发之OC基础-oc小程序

    本系列的文章主要来自于个人在学习前锋教育-欧阳坚老师的iOS开发教程之OC语言教学视频所做的笔记,边看视频,边记录课程知识点.建议大家先过一遍视频,在看视频的过程中记录知识点关键字,把把握重点,然后再 ...

  7. Track files and folders manipulation in Windows

    The scenario is about Business Secret and our client do worry about data leakage. They want to know ...

  8. 设计模式-单例模式(Singleton)

    模式说明: 保证每一个类仅有一个实例,并提供一个访问它的全局访问点(即自行实例化并向整个系统提供这个实例). 应用场景: 1.如配置文件取值类AppConfig(本身实例化对象比较大,且没有必要实例化 ...

  9. s3c6410_MMU地址映射过程详述

    参考: 1)<ARM1176 JZF-S Technical Reference Manual>: Chapter 3 System Control Coprocessor Chapter ...

  10. DataGridView 控件用法(可能不是很全面,因为这是自己常常用到的一些小总结):

    一.DataGridView属性设置 1.我们单击选中行的时候,默认是选择一个单元格,不能选择一整行,我们只需设置DataGridView的属性SelectionMode为FullRowSelect ...