Java的Socket网络编程基础知识入门教程
作者:cdai 发布时间:2021-11-19 10:10:37
一、TCP/IP简介
TCP/IP协议族是互联网使用的协议,也可以用在独立的专用网络中。
TCP/IP协议族包括了IP协议、TCP协议和UDP协议。
IP协议使用IP地址来分发报文,但它是尽力而为的服务,报文可能丢失、乱序或者
重复发送。TCP和UDP协议在IP协议基础上增加了端口号,从而在两台主机的应用
程序间建立起透明的连接。
不同的是,TCP协议会对IP层的错误进行修复,它通过握手消息在主机间建立连接,
之后通过在消息中加入序列号来恢复消息中的错误。而UDP只是简单地扩展了IP协议,
使它能够在应用程序之间工作,而不是主机之间。
关于IP地址,一台主机可以有多个网络接口,而一个接口又可以有多个地址。
有些IP地址是有特殊用途的:
A.回环地址:127.0.0.1,总是被分配给一个回环接口,主要用于测试。
B.私有地址:以10、192.168、172.(16-31)开头,用于私有网络。NAT设备转发报文
时,将一个接口中报文的私有地址端口对映射成另一个接口中的公有地址端口对。这
就使一小组主机能够共享一个IP地址对。
C.多播地址:第一个数字在224~239之间。
二、Socket基础
1.地址的获得
public static void main(String[] args) {
try {
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface iface = interfaces.nextElement();
System.out.println("Interface: " + iface.getName());
Enumeration<InetAddress> addrList = iface.getInetAddresses();
if (!addrList.hasMoreElements())
System.out.println("No address");
while (addrList.hasMoreElements()) {
InetAddress address = addrList.nextElement();
System.out.println("Address: " + address.getHostAddress());
}
}
} catch (SocketException e) {
e.printStackTrace();
}
}
2.TCP实例程序
要注意一点,虽然在Client端只用了一个write()方法发送字符串,服务器端也可能从
多个块中接受该信息。即使回馈字符串在服务器返回时存于一个块中,也可能被TCP
协议分割成多个部分。
TCPEchoClientTest.java
public static void main(String[] args) throws IOException {
String server = args[0];
byte[] data = args[1].getBytes();
int port = 7;
Socket socket = new Socket(server, port);
System.out.println("Connected to server...");
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
out.write(data);
int totalBytesRcvd = 0;
int bytesRcvd;
while (totalBytesRcvd < data.length) {
if ((bytesRcvd = in.read(data, totalBytesRcvd,
data.length - totalBytesRcvd)) == -1)
throw new SocketException("Connection closed");
totalBytesRcvd += bytesRcvd;
}
System.out.println("Received: " + new String(data));
socket.close();
}
TCPEchoServerTest.java
private static final int BUFSIZE = 32;
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(7);
int recvMsgSize;
byte[] receiveBuf = new byte[BUFSIZE];
while (true) {
Socket socket = serverSocket.accept();
System.out.println("Handling client " +
" from remote " + socket.getRemoteSocketAddress() +
" at local " + socket.getLocalSocketAddress());
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
while ((recvMsgSize = in.read(receiveBuf)) != -1) {
out.write(receiveBuf, 0, recvMsgSize);
}
socket.close();
}
}
注意new Socket时指定的是远端服务器监听的端口号而没有指定本地端口,因此将
采用默认地址和可用的端口号。在我的机器上Client端口是4593,连接到服务器的
端口7。
3.UDP实例程序
为什么使用UDP协议?如果应用程序只交换少量的数据,TCP连接的建立阶段就至少
要传输其两倍的信息量(还有两倍的往返时间)。
UDPEchoClientTest.java
public static void main(String[] args) throws IOException {
InetAddress serverAddress = InetAddress.getByName(args[0]);
byte[] bytesToSend = args[1].getBytes();
DatagramSocket socket = new DatagramSocket();
socket.setSoTimeout(3000);
DatagramPacket sendPacket = new DatagramPacket(
bytesToSend, bytesToSend.length, serverAddress, 7);
DatagramPacket receivePacket = new DatagramPacket(
new byte[bytesToSend.length], bytesToSend.length);
// Packets may be lost, so we have to keep trying
int tries = 0;
boolean receivedResponse = false;
do {
socket.send(sendPacket);
try {
socket.receive(receivePacket);
if (!receivePacket.getAddress().equals(serverAddress))
throw new IOException("Receive from unknown source");
receivedResponse = true;
}
catch (IOException e) {
tries++;
System.out.println("Timeout, try again");
}
} while (!receivedResponse && tries < 5);
if (receivedResponse)
System.out.println("Received: " + new String(receivePacket.getData()));
else
System.out.println("No response");
socket.close();
}
UDPEchoServerTest.java
private static final int ECHOMAX = 255;
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(7);
DatagramPacket packet = new DatagramPacket(new byte[ECHOMAX], ECHOMAX);
while (true) {
socket.receive(packet);
System.out.println("Handling client at " + packet.getAddress());
socket.send(packet);
packet.setLength(ECHOMAX);
}
}
通过这个例子与之前TCP的实例进行比较,有如下区别:
A.DatagramSocket在创建时不需要指定目的地址,因为UDP不需要建立连接,每个
数据报文都可以发送或接收于不同的目的地址。
B.如果像TCP一样在read()上阻塞等待,将可能永远阻塞在那里,因为UDP协议只是
简单地扩展了IP协议,UDP报文可能丢失掉。所以一定要设置阻塞等待的超时时间。
C.UDP协议保留了消息的边界信息,每次receive()调用最多只能接收一次send()方法
调用所发送的数据。
D.一个UDP报文DatagramPacket能传输的最大数据是65507字节,超出部分的字节将
自动被丢弃,而且对接收程序也没有任何的提示。因此缓存数组可以设置成65000字节
左右是安全的。
E.如果反复使用同一个DatagramPacket实例调用receive()方法,每次调用前都必须显式
地将消息的内部长度重置为缓存区的实际长度。


猜你喜欢
- AndroidStudio终于出3.0正式版了,内置了kotlin(虽然我安了插件一直能用)。一直忍着没敢下rc版的好奇猫,总算装了正式版。
- 使用要点如下:1.利用ListAdapter(一般使用ArrayAdapter)为AutoCompleteTextView提供数据,若有需要
- 本文实例为大家分享了Java通讯录系统的具体代码,供大家参考,具体内容如下import java.util.Scanner;class Pe
- 概述对List进行分组是日常开发中,经常遇到的,在JDK 8中对List按照某个属性分组的代码,超级简单。package test;impo
- 使用python和java实现数独游戏,有比较才有收获哦。1、Python版#--coding:utf-8--import ra
- 一、程序的三种结构顺序结构分支结构循环结构二、条件语句if 语句是最有用的控制结构之一。 if … else …语句的语法:if (布尔表达
- java 8的新特性之一就是lambda表达式,parallelStream()都说性能会比较高,现一探究竟。话不多说,上代码: @Test
- 最近做的项目有一个要求,就是在WebView中显示的html,需要在点击其中的图片时进行放大,并进行缩放和滑动 浏览,我第一想到的是这是和j
- 本文实例为大家分享了C#二维码图片识别的具体代码,供大家参考,具体内容如下怎么用NuGet和怎么配置log4net就不介绍了,直接上代码(V
- 使用POI读写Word doc文件 Apache poi的hwpf模
- 安装容易出现的问题以及解决方法:1、更新sdk时可能无法连接服务器,可在C:\WINDOWS\system32\drivers\etc下的h
- 前言记得去年做一个聊天项目需要实现类似QQ的下拉刷新并且有侧滑删除的功能,在网上找了很久都没有QQ的完美,多多少少存在各种的问题,最后把下拉
- Springboot添加server.servlet.context-pathserver.servlet.context-path配置的作
- 一、FileZillaFilezilla分为client和server。其中FileZilla Server是Windows平台下一个小巧的
- 本篇内容通过操作软键盘的函数着手详细分析了隐藏或者显示软键盘的实现方法,并且对其中重要的代码做了详细分析。一、开篇如果有需要用到输入的地方,
- 一、负载均衡负载均衡(Load Balance): 建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞
- 本猿今天今天帮公司写第三支付接口的时候,灵机一动就想写一个扩展性比较的强的充值接口,t通过选择不同的充值渠道,调用不同的充值实现类(好了,废
- 提示出现unresolved external symbol _main搜了下找了下原因如下在创建MFC项目时
- springboot天生支持使用hibernate validation对参数的优雅校验,如果不使用它,只能对参数挨个进行如下方式的手工校验
- 本文实例为大家分享了Java Web实现简易图书管理系统的具体代码,供大家参考,具体内容如下前言首先实现的是用户的登录注册,注册成功后自动跳