标签:而且 解析 pcl tle 客户端连接 流程 服务器端 put 会话
Socket独立于具体协议的网络编程接口,在ISO模型中,主要位于会话层和传输层之间;在通用的计算机网络五层模型中,主要位于应用层和传输层之间。
套接字是一种通信机制,通信两方的一种约定,用套接字中的相关函数来完成通信过程。根据传输内容分为流式套接字、数据报套接字、原始套接字;根据使用方式分为主动套接字和被动套接字。
提供了一个面向连接、可靠的数据传输服务,数据无差错、无重复的发送且按发送顺序接收。内设置流量控制,避免数据流淹没慢的接收方。数据被看作是字节流,无长度限制。(面向TCP)
提供无连接服务。数据包以独立数据包的形式被发送,不提供无差错保证,数据可能丢失或重复,顺序发送,可能乱序接收。(面向UDP)
可以对较低层次协议,如IP、ICMP直接访问。
创建方式相同,使用方式不同
指明端点地址:创建时不指定,使用时指明:
TCP下通信调用Linux Socket API流程如下:
UDP下通信调用Linux Socket API流程如下:
int socket( int domain, int type, int protocol)
功能:创建一个新的套接字,返回套接字描述符
参数说明:
举例:s=socket(PF_INET,SOCK_STREAM,0)
int connect(int sockfd,struct sockaddr *server_addr,int sockaddr_len)
功能: 同远程服务器建立主动连接,成功时返回0,若连接失败返回-1。
参数说明:
int bind(int sockfd,struct sockaddr * my_addr,int addrlen)
功能:为套接字指明一个本地端点地址TCP/IP协议使用sockaddr_in结构,包含IP地址和端口号,服务器使用它来指明熟知的端口号,然后等待连接
参数说明:
举例:bind(sockfd, (struct sockaddr *)&address, sizeof(address));
int listen(int sockfd,int input_queue_size)
功能:面向连接的服务器使用它将一个套接字置为被动模式,并准备接收传入连接。用于服务器,指明某个套接字连接是被动的
参数说明:
举例:listen(sockfd,20)
int accept(int sockfd, void *addr, int *addrlen);
功能:获取传入连接请求,返回新的连接的套接字描述符。为每个新的连接请求创建了一个新的套接字,服务器只对新的连接使用该套接字,原来的监听套接字接受其他的连接请求。新的连接上传输数据使用新的套接字,使用完毕,服务器将关闭这个套接字。
参数说明:
举例:new_sockfd = accept(sockfd, (struct sockaddr *)&address, &addrlen);
int sendto(int sockfd, const void * data, int data_len, unsigned int flags, struct sockaddr *remaddr,int remaddr_len)
功能:基于UDP发送数据报,返回实际发送的数据长度,出错时返回-1
参数说明:
举例:sendto(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&address, sizeof(address));
int recvfrom(int sockfd, void *buf, int buf_len,unsigned int flags,struct sockaddr *from,int *fromlen);
功能:从UDP接收数据,返回实际接收的字节数,失败时返回-1
参数说明:
举例:recvfrom(sockfd,buf,8192,0, ,(struct sockaddr *)&address, &fromlen);
int send(int sockfd, const void * data, int data_len, unsigned int flags)
功能:在TCP连接上发送数据,返回成功传送数据的长度,出错时返回-1。send会将外发数据复制到OS内核中
参数说明:
举例:send(s,req,strlen(req),0);
int recv(int sockfd, void *buf, int buf_len,unsigned int flags);
功能:从TCP接收数据,返回实际接收的数据长度,出错时返回-1。服务器使用其接收客户请求,客户使用它接受服务器的应答。如果没有数据,将阻塞,如果收到的数据大于缓存的大小,多余的数据将丢弃。
参数说明:
举例:recv(sockfd,buf,8192,0)
close(int sockfd);
功能:撤销套接字。如果只有一个进程使用,立即终止连接并撤销该套接字,如果多个进程共享该套接字,将引用数减一,如果引用数降到零,则撤销它。
参数说明:
举例:close(socket_descriptor)
1.IP地址转换函数
java.net.Socket继承于java.lang.Object,有八个构造器,其方法并不多。套接字Socket已经写好封装在java.net.Socket包里。服务器端有特定的ServerSocket方法。
ServerSocket有以下3个属性:
对于Socket类有如下常用方法:
注意:其中getInputStream和getOutputStream方法均会产生一个IOException,它必须被捕获,因为它们返回的流对象,通常都会被另一个流对象使用。
多线程下的TCP服务器端:
package socketLearn;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpServerChat {
public static void main(String[] args) throws IOException {
System.out.println("--------Server--------");
ServerSocket server = new ServerSocket(8888);
//1. 指定端口,使用ServerSocket创建服务器
while(true){
//2. 阻塞地等待连接
Socket socket = server.accept();
System.out.println("一个客户端建立了连接");
new Thread(()->{
DataInputStream dis = null;
DataOutputStream dos = null;
BufferedReader br= new BufferedReader(new InputStreamReader(System.in));;
try {
dis = new DataInputStream(socket.getInputStream());
dos = new DataOutputStream(socket.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
boolean isRunning = true;
while(isRunning){
try {
//3. 接收消息
String msg = dis.readUTF();
System.out.println("客户端说:"+msg);
//4.返回消息
String reMsg = br.readLine();
dos.writeUTF(reMsg);
dos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
dis.close();
socket.close();
server.close();
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
}
}
多线程下的TCP客户端:
package socketLearn;
import java.io.*;
import java.net.Socket;
public class TcpClientChat {
public static void main(String[] args) throws IOException {
System.out.println("--------Client--------");
//1. 建立连接,使用Socket创建客户端
Socket client = new Socket("localhost",8888);
boolean isRunning = true;
BufferedReader console = new BufferedReader((new InputStreamReader(System.in)));
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
DataInputStream dis = new DataInputStream(client.getInputStream());
while(isRunning){
//2. 客户端发送消息
String msg = console.readLine();
dos.writeUTF(msg);
dos.flush();
//3. 获取消息
msg = dis.readUTF();
System.out.println("服务器说:"+msg);
}
dos.close();
dis.close();
client.close();
}
}
正常来说,客户端打开一个输出流,如果不做约定,也不关闭它,那么服务端永远不知道客户端是否发送完消息,那么服务端会一直等待下去,直到读取超时。
socket关闭输出流
socket.shutdownOutput();
注意不能使用outputStream.close(),若用该法关闭了输出流,那么相应的Socket也将关闭,和直接关闭Socket一个性质。
通过约定的符号
双方约定一个字符或者一个短语,来当做消息发送完成的标识,通常这么做就需要改造读取方法(读取的循环条件)。
使用DataInputStream、DataOutputStream对socket.getOutputStream,socket.getInputStream进行包装
1、使用DatagramSocket 指定端口创建接收端
2、准备容器封装成DatagramPacket包裹
3、阻塞式接收包裹receive(DatagramPacket p)
4、分析数据byte[] getData();getLength();
5、释放资源
public class UdpServer {
public static void main(String[] args) throws Exception{
System.out.println("接收方启动中...");
DatagramSocket server = new DatagramSocket(9999);
byte[] container = new byte[1024*60];
DatagramPacket packet = new DatagramPacket(container, 0,container.length);
server.receive(packet);
byte[] datas = packet.getData();
int len = packet.getLength();
System.out.println(new String(datas,0,len,"UTF-8"));
server.close();
}
}
1、使用DatagramSocket 指定端口创建发送端
2、准备数据一定转成字节数组
3、封装成DatagramPacket包裹,需要指定目的地4、发送包裹send(DatagramPacket p)
5、释放资源
public class UdpClient {
public static void main(String[] args) throws Exception{
System.out.println("发送方启动中...");
DatagramSocket client = new DatagramSocket(8888);
String data = "改革春风吹满地";
byte[] datas = data.getBytes();
DatagramPacket packet = new DatagramPacket(datas, 0,datas.length,
new InetSocketAddress("localhost",9999));
client.send(packet);
client.close();
}
}
Java Socket编程以及与Linux Socket API关系
标签:而且 解析 pcl tle 客户端连接 流程 服务器端 put 会话
原文地址:https://www.cnblogs.com/zerolin77/p/12014077.html