Socket(1)
端口号可以从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();
}
}
}
}
运行:
- 先运行Server再运行Client
- 在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();
}
}
运行:
- 先运行Server再运行Client
Socket(1)的更多相关文章
- socket读写返回值的处理
在调用socket读写函数read(),write()时,都会有返回值.如果没有正确处理返回值,就可能引入一些问题 总结了以下几点 1当read()或者write()函数返回值大于0时,表示实际从缓冲 ...
- Socket聊天程序——Common
写在前面: 上一篇记录了Socket聊天程序的客户端设计,为了记录的完整性,这里还是将Socket聊天的最后一个模块--Common模块记录一下.Common的设计如下: 功能说明: Common模块 ...
- Socket聊天程序——客户端
写在前面: 上周末抽点时间把自己写的一个简单Socket聊天程序的初始设计和服务端细化设计记录了一下,周二终于等来毕业前考的软考证书,然后接下来就是在加班的日子度过了,今天正好周五,打算把客户端的详细 ...
- Socket聊天程序——服务端
写在前面: 昨天在博客记录自己抽空写的一个Socket聊天程序的初始设计,那是这个程序的整体设计,为了完整性,今天把服务端的设计细化记录一下,首页贴出Socket聊天程序的服务端大体设计图,如下图: ...
- Socket聊天程序——初始设计
写在前面: 可能是临近期末了,各种课程设计接踵而来,最近在csdn上看到2个一样问答(问题A,问题B),那就是编写一个基于socket的聊天程序,正好最近刚用socket做了一些事,出于兴趣,自己抽了 ...
- Java中的Socket的用法
Java中的Socket的用法 Java中的Socket分为普通的Socket和NioSocket. 普通Socket的用法 Java中的 ...
- Android Socket连接PC出错问题及解决
最近测试问题:Android 通过Socket链接电脑,ip和端口都是正确的,也在同一网段,可android端就是报异常如下: 解决办法:测试电脑的防火墙可能开着,在控制面板把防火墙打开即可.
- Linux下的C Socket编程 -- server端的继续研究
Linux下的C Socket编程(四) 延长server的生命周期 在前面的一个个例子中,server在处理完一个连接后便会立即结束掉自己,然而这种server并不科学啊,server应该是能够一直 ...
- Mono 3.2.3 Socket功能迎来一稳定的版本
由于兴趣自己业余时间一直在搞.net下面的通讯应用,mono的存在得以让.NET程序轻松运行在Linux之下.不过经过多尝试Socket相关功能在Mono下的表现并不理想.不管性能还是吞吐能力方面离我 ...
- Demo源码放送:打通B/S与C/S !让HTML5 WebSocket与.NET Socket公用同一个服务端!
随着HTML5 WebSocket技术的日益成熟与普及,我们可以借助WebSocket来更加方便地打通BS与CS -- 因为B/S中的WebSocket可以直接连接到C/S的服务端,并进行双向通信.如 ...
随机推荐
- SQL 表值函数
表值函数返回的是一张表. 情况:把传入的字符串按指定分隔符转换成数组 理解:把字符串打散,逐个插入表,这个表就是需要的数据 Create Function [dbo].[Split] ( ), ) ) ...
- startup毕业论文
今天起得相对比较晚,为的是一个没有目的面试,去了的结果.只是打击一下自己的自信心,走的时候,面试官冷冷的说了一句,你的面试到此结束,是的,我并没有很伤心,在门外等面试的时候,我就非常的后悔,今天是不该 ...
- 洛谷P2731 骑马修栅栏 Riding the Fences
P2731 骑马修栅栏 Riding the Fences• o 119通过o 468提交• 题目提供者该用户不存在• 标签USACO• 难度普及+/提高 提交 讨论 题解 最新讨论 • 数据有问题题 ...
- 25_android下文件访问的权限
写文件:FileOutputStream fos = 上下文.openFileOutput("private.txt",Context.MODE_PRIVATR);参数1 文件名, ...
- Mac OS X Server 安装与应用
Mac OS X Server 安装与应用 Mac OS X Server是苹果电脑公司新一代服务器软件.专为OS X和iOS设备.Mac OS X提供服务,现在支持Mavericks,能够轻松共享文 ...
- 集群监控系统Ganglia应用案例
集群监控系统Ganglia应用案例 --我们把集群系统投入生产环境后,这时就需要一套可视化的工具来监视集群系统,这将有助于我们迅速地了解机群的整体配置情况,准确地把握机群各个监控节点的信息,全面地察看 ...
- json与gson
json:java中将json字符串转换成实体对象时,key值不能大写.将实体对象转换成json时,会默认把key值改成小写 gson:java中将json字符串转换成实体对象时,要与实体对象的字段值 ...
- 【Linux】Zabbix + MPM + msmtp + mutt 监控MySQL + 邮件报警
Zabbix部署参考博文 http://blog.sina.com.cn/s/blog_5611597901017oe0.html MPM安装配置参考博文和MPM官网下载地址 http://blog ...
- PHP生成静态页面的方法
在PHP网站开发中为了网站推广和SEO等需要,需要对网站进行全站或局部静态化处理,PHP生成静态HTML页面有多种方法,比如利用PHP模板.缓存 等实现页面静态化,今天就以PHP实例教程形 ...
- 简短总结一下C#里跨线程更新UI
摘自: http://my.oschina.net/sdqxcxh/blog/53707 跨线程更新UI是写多线程程序尤其是通信类的程序经常遇到的问题,这里面主要的问题是冲突,比如数据线程想要更新UI ...