Java网络编程
java网络编程
一.几个相关概念及对应java提供的类
1.ip、域名(会帮我们解析成ip)
InetAddress
package net;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class IpDemo {
public static void main(String[] args) throws Exception {
InetAddress myAddr=InetAddress.getLocalHost();
InetAddress baiduAddr=InetAddress.getByName("www.baidu.com");
System.out.println(myAddr.getHostAddress());
System.out.println(baiduAddr.getHostAddress());
}
}
知道有这么个类即可,是代表IP地址的类,方法基本都可以从名字看出来。
2.ip+端口,识别一个进程的类
InetSocketAddress
InetSocketAddress sock=new InetSocketAddress("localhost",80);
System.out.println(sock.getAddress()+" "+sock.getPort());
3.URL(具体到某个地址上的具体资源路径 ,跟资源的具体内容无关)
URL url = new URL("http://www.baidu.com:80/index.html?uname=bjsxt");
System.out.println("协议:"+url.getProtocol());
System.out.println("域名:"+url.getHost());
System.out.println("端口:"+url.getPort());
System.out.println("资源:"+url.getFile());
System.out.println("相对路径:"+url.getPath());
System.out.println("锚点:"+url.getRef()); //锚点
System.out.println("参数:"+url.getQuery());//?参数 :存在锚点 返回null ,不存在,返回正确
二.UDP聊天实践
package net;
import com.alibaba.fastjson.JSON;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class MyServer extends Thread {
int port;
MyServer(int port){
this.port=port;
}
@Override
public void run() {
DatagramSocket server= null;
try {
server = new DatagramSocket(port);
} catch (SocketException e) {
e.printStackTrace();
}
while (true)
{
byte[] container = new byte[1024];
DatagramPacket packet=new DatagramPacket(container,container.length);
try {
server.receive(packet);
} catch (IOException e) {
e.printStackTrace();
}
Message m1= JSON.parseObject(packet.getData(),Message.class);
System.out.println(m1.getSender()+": "+m1.getData());
}
// server.close();
}
}
- DatagramSocket(数据报套接字),在某个端口上实现监听(接收客户端的数据请求)
- 请求的报文 DatagramPacket,packet.getData()拿到收到的数据(为byte数组,需要进行转换,这里使用fastJson进行转换)
package net;
import com.alibaba.fastjson.JSON;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.util.Scanner;
public class MyClient extends Thread {
int port;
String name;
int myport;
MyClient(String name,int myport,int port){
this.name=name;
this.myport=myport;
this.port=port;
}
@Override
public void run() {
DatagramSocket client = null;
try {
client = new DatagramSocket(myport);
} catch (SocketException e) {
e.printStackTrace();
}
Message message=new Message();
message.setSender(name);
Scanner sc=new Scanner(System.in);
while(true)
{
String data=sc.nextLine();
message.setData(data);
byte[] datas= JSON.toJSONBytes(message);
DatagramPacket packet = new DatagramPacket(datas,datas.length,new InetSocketAddress("localhost",port));
try {
client.send(packet);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(message.getSender()+": "+message.getData());
if(data.equals("bye"))
break;
}
}
}
- 服务端只需要在某个端口监听,客户端需要两个端口(一个本地端口用来发送,一个是服务器接收你请求的端口)
- client = new DatagramSocket(myport); 先通过DataGtamSocket 打开一个本地的端口
- 再通过DatagramPacket封装一个数据包对象,并注明接收方的InetSocketAddress(IP与端口)
- send把包发出去
三 TCP聊天室实践
1.服务器程序,不断运行接收每个客户端的消息
public class ChatServer {
// 容器来存放每一个channel管道
private List<MyChannel> all = new ArrayList<MyChannel>();
public static void main(String[] args) throws IOException {
ChatServer server=new ChatServer();
server.start();
}
private void start() throws IOException {
ServerSocket server=new ServerSocket(8888);
while(true){
Socket client =server.accept();
MyChannel channel = new MyChannel(client);
all.add(channel);//统一管理
new Thread(channel).start(); //一条道路
}
}
关键点解析:
- 每个客户端连上后形成了一个输入输出流,相当于产生了一条channel,这条channel的输出流需要输入给其他n-1个客户端(让其他客户端可以收到数据),因此需要一个容器List来存储所有客户端的channel . List
all - 服务器通过一个while True保证一直接收客户端的请求,当一个请求进来后(server.accept()),给他一个channel,并且这个channel必须是一个线程,放旁边接着继续运行维护这个客户端的需要。
public MyChannel(Socket client ) throws IOException {
dis = new DataInputStream(client.getInputStream());
dos = new DataOutputStream(client.getOutputStream());
this.name =dis.readUTF();
// 返回给他自己
this.send("欢迎您进入聊天室");
this.sendOthers(this.name+"进入了聊天室",true);
}
channel构造函数关键点解析:
- 每个channel都有输入输出流,当新建一个channel的时候,dis就是client的inputStream,dos就是client的outputStream.
private void send(String msg) throws IOException {
if(null==msg ||msg.equals("")){
return ;
}
try {
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
//e.printStackTrace();
dis.close();
dos.close();
all.remove(this); //移除自身
}
}
send函数关键点解析:
- dos将msg发出去
private void sendOthers(String msg,boolean sys) throws IOException {
//是否为私聊 约定
if(msg.startsWith("@")&& msg.indexOf(":")>-1 ){ //私聊
//获取name
String name =msg.substring(1,msg.indexOf(":"));
String content = msg.substring(msg.indexOf(":")+1);
for(MyChannel other:all){
if(other.name.equals(name)){
other.send(this.name+"对您悄悄地说:"+content);
}
}
}else{
//遍历容器
for(MyChannel other:all){
if(other ==this){
continue;
}
if(sys){ //系统信息
other.send("系统信息:"+msg);
}else{
//发送其他客户端
other.send(this.name+"对所有人说:"+msg);
}
}
}
}
send函数关键点解析:
- @开头 并且有对象的时候,为私聊,此时从channel中找出私聊的channel的name,调用该条channel的send函数发送数据。
2.如果为群聊,则遍历all容器,除自身外所有容器都调用send函数,发给其他每个人。

浙公网安备 33010602011771号