-
2022-02-19 21:25:17
Socket通信学习笔记(一)不同语言间socket通信连接
实现不同语言作为服务端客户端,实时返回服务端结果。 C#为服务端,python为客户端
前言
要求在c#端调用python程序实时得到结果,返回给C#端进行处理。使用Socket通信在本机连接两个程序,服务端由C#实现,客户端由python实现。为了更好的使用,将服务端和客户端封装为类,对外提供使用接口。
一、服务端(C#)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net; using System.Net.Sockets; namespace ServerManySelf { class Server { private TcpListener listener;//监听 private NetworkStream streamToClient;//流对象 private TcpClient remoteClient; private int BufferSize = 1024;//缓存大小,结果返回只需要个位数,改大会多条信息合并为一条接收 /// <summary> /// 构造函数 /// 创建服务端连接实例 /// </summary> public Server() { Console.WriteLine("Server is running ..."); IPAddress ip = IPAddress.Parse("127.0.0.1");//获取ip地址 listener = new TcpListener(ip, 8500); listener.Start();//开始监听 Console.WriteLine("Start Listening..."); //获取一个连接,中断方法 remoteClient = listener.AcceptTcpClient(); //打印连接到的客户端信息 Console.WriteLine("Client Connected! {0}<--{1}", remoteClient.Client.LocalEndPoint, remoteClient.Client.RemoteEndPoint); //获取流,并写入buffer中 streamToClient = remoteClient.GetStream(); } /// <summary> /// 获取客户端传入消息 /// </summary> /// <returns></returns> public string GetMessage() { byte[] buffer = new byte[BufferSize]; int bytesRead = streamToClient.Read(buffer, 0, BufferSize);//一直等待客户端传信息 Console.WriteLine("Reading data,{0} bytes...", bytesRead); //获得请求的字符串 string msg = Encoding.UTF8.GetString(buffer, 0, bytesRead); //string msg = Encoding.Unicode.GetString(buffer, 0, bytesRead); return msg; } /// <summary> /// 关闭服务端连接 /// </summary> public void close() { listener.Stop(); } } }
二、客户端(python)
from socket import * class Client: tcpCliSock = 0 def __init__(self): HOST = '127.0.0.1' # or 'localhost' PORT = 8500 BUFSIZ = 1 ADDR = (HOST, PORT) self.tcpCliSock = socket(AF_INET, SOCK_STREAM) self.tcpCliSock.connect(ADDR) def _send(self, data1): self.tcpCliSock.send(data1.encode('utf-8')) def _close(self): self.tcpCliSock.close()
三、使用
c#端为服务端,python端为客户端
通过127.0.0.1和端口8500连接
c#关于socket的操作都封装为Server类,提供初始化构建服务端,获取客户端传入信息和关闭服务端函数。
using ServerManySelf; //引入Server类的命名空间 Server s = new Server();//创建服务端 //循环保证服务端一直监听客户端信息 string msg = s.GetMessage();//获取客户端传入信息 s.close(); //关闭服务端
python关于socket的操作都封装为Client类,提供初始化,发送信息,关闭客户端函数
from Client import * #引入Client类 client = Client() # 初始化构造一个客户端 client._send(msg) #发送信息,msg必须为string类型 client._close() #关闭客户端
先运行C#的program开启服务端,再运行python的test01开启客户端发送信息。
总结
当客户端快速发送多条语句时,send函数不会每次都发给服务端,而是会多条语句合并为一句一并发送,语句长度与服务端缓存大小有关。
demo在仓库,欢迎指正错误,如果对你有帮助欢迎star和fork。
也可以在这里下载。更多相关内容 -
windows下socket通信代码
2017-12-27 10:34:02windows下socket通信代码,带注释,适合初学者;包含客户端和服务器两个文件 -
SpringMVC的Socket实现+Java Tomcat websocket实现+Java Socket通信实现 +Java UDP通信实现
2018-07-31 18:22:05SpringMVC的Socket实现+Java Tomcat websocket实现+Java Socket通信实现 +Java UDP通信实现。websocket_study.rar 为springMVC版本的socket实现 websocket02.rar 里面包含tomcat的websocket实现+java socket双向通信... -
socket通信与串口通信(二选择一)
2022-07-27 08:41:33什么是socket通信? TCP/IP协议是传输层协议,主要解决数据如何在网络中传输。HTTP是应用层协议,主要解决如何包装数据。 Socket是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的... -
linux和windows之间的socket通信代码
2015-05-06 16:40:32socket_test.c文件放到linux环境下,用gcc进行编译,运行。 socket_test文件夹用VC++6.0打开运行,就可以实现windows和 linux间简单的通讯,能够进行字符的收发。 -
Java实现Socket通信
2021-06-04 17:28:30在掌握了基本的理论后,想通过编程实践,来巩固和加深下对Socket通信的理解。 一 项目简介 1. 开发环境 操作系统:win10 Java版本:1.8 开发工具:IDEA 2021 2. 项目描述 本项目基于TCP协议,实现了客户端和服务器...前言:花了一个多星期的时间,重新学习了计算机网络中可靠数据传输的知识和TCP、UDP协议。在掌握了基本的理论后,想通过编程实践,来巩固和加深下对Socket通信的理解。
一 项目简介
1. 开发环境
操作系统:win10
Java版本:1.8
开发工具:IDEA 20212. 项目描述
本项目基于TCP协议,实现了客户端和服务器的Socket通信。项目主要实现了查字的功能,客户端输入要查询的一个汉字,然后回车发送到服务器端,服务器把汉字的查询结果在返回给客户端。另外,在使用服务器提供的字典服务前,客户端需要先进行登录。
3. 运行效果
二、TCP
1、 TCP协议
TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。它将两个端系统(或主机)间IP的交付服务扩展到了运行在端系统上的两个进程之间的交付服务。举个容易理解的真实例子,我们学校说是为了安全不允许外卖员把外卖送到寝室里,并且我们假设食堂的各家餐厅生产的外卖有人负责把它们拿到楼下的统一地点。外卖小哥(IP协议)根据外卖地址(IP地址)负责把外卖拿到我们住的宿舍楼下(目的主机),宿管阿姨(TCP协议)根据姓名(端口号)负责把外卖分发到具体的学生(进程)手里
2、套接字
TCP套接字的标识:是一个四元组【源主机IP、源端口号、目的主机IP、目的端口号】。
TCP套接字的作用:多路分解和多路复用。
多路分解:将运输层的报文段中的数据交付到正确的套接字的工作称为多路分解,之后应用层的进程会从它绑定的套接字中获取数据。
多路复用:在源主机从不同套接字中收集数据块,并为每个数据块封装上首部信息(主要是端口号,这将用于分解)从而生成报文段,然后将报文段传递到网络,这些工作称为多路复用。从某方面来说:IP是主机的标识,端口号是进程的标识
3. TCP连接(很重要)
TCP连接是两个端系统(源主机和目的主机)中的状态信息。位于因特网核心的网路元素(路由器和链路层交换机)只运行IP协议,TCP只运行在端系统中,因此TCP连接一条逻辑的连接,只是两个端系统中的状态信息,即源主机知道目的主机的存在,目的主机也知道源主机的存在。
TCP连接的组成包括:一台主机上的缓存(数据缓冲区)、变量(序号、窗口等信息)和与进程连接的套接字,以及另一台主机上的缓存、变量和套接字。关于为什么是三次握手建立TCP连接及序号的重要性,有些博文介绍的已经什么透彻了,不要在这里再次叙述,推荐TCP 为什么三次握手而不是两次握手(正解版)
4. TCP连接建立的过程
1.TCP服务器端,选择了一个端口号,如8080,开启了一个进程,来“监听”此端口,等待来自TCP客户端的连接建立请求。此时的套接字标识为【0.0.0.0:0,目的主机ip:8080】,此套接字称为“欢迎套接字”,用于建立TCP连接,并不用于数据传输
2.TCP客户端进程创建了一个套接字发送了一个连接建立请求报文段(SYN置为1,还包含客户端为进程选择的端口号如10000)
3.TCP服务端进程监听到客户端的连接建立请求,创建子进程(或线程)和套接字,称为“连接套接字”,用于和客户端的数据传输。
此时TCP连接已经建立,后续有新的连接建立请求,则重复上述过程。如果TCP发送数据,则会根据检查套接字,根据套接字把数据交付给对应的进程,即多路分解。
三 项目代码
1 服务器端
package com.gzn.server; import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.util.HashMap; import java.util.Map; public class Main { private static class ServerMsg{ public static final String WELCOMING = "欢迎使用《明月几时有字典》,请按照提示操作。注:回车后可提交信息,查询汉字为“#”表示退出!"; public static final String INPUT_USERNAME = "请输入用户名:"; public static final String INPUT_PASSWORD = "请输入密码:"; public static final String LOGIN_SUCCEED_CODE = "1001"; public static final String LOGIN_FAIL_CODE = "1002"; public static final String NOT_FOUND_CODE = "2001"; } // 用户列表 private static Map<String, String> users; private static Map<String, String> dict; // 初始化用户列表和字典 private static void init(){ // 初始化用户 users = new HashMap<>(); users.put("admin", "123123"); // 初始化字典 dict = new HashMap<>(); dict.put("明", "【读音:ming】" + "组词:明天、明亮"); dict.put("月", "【读音:yue】" + "组词:月亮、月光"); dict.put("几", "【读音:ji】" + "组词:几个、几乎"); dict.put("时", "【读音:shi】" + "组词:时间、小时"); dict.put("有", "【读音:you】" + "组词:没有"); } private static class Worker implements Runnable{ private Socket connectionSocket; private PrintWriter sendBuffer; private BufferedReader recvBuffer; public Worker(Socket connectionSocket) throws IOException { this.connectionSocket = connectionSocket; sendBuffer = new PrintWriter(new OutputStreamWriter(connectionSocket.getOutputStream(), "UTF-8"), true); recvBuffer = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream(), "UTF-8")); } private void welcoming() throws IOException { send(ServerMsg.WELCOMING); } private void login() throws IOException { boolean flag = false; while(!flag){ send(ServerMsg.INPUT_USERNAME); String username = receive(); send(ServerMsg.INPUT_PASSWORD); String password = receive(); if (users.get(username) != null && users.get(username).equals(password)){ send(ServerMsg.LOGIN_SUCCEED_CODE); flag = true; }else { send(ServerMsg.LOGIN_FAIL_CODE); } } } private boolean contains(String word){ return dict.containsKey(word); } private String lookup(String word) throws IOException { return dict.get(word); } /** * 向套接字的发送缓存写入信息 * @throws IOException */ private void send(String msg) throws IOException{ sendBuffer.println(msg); } /** * 从套接字的接收缓存读取信息 * @return * @throws IOException */ private String receive() throws IOException{ return recvBuffer.readLine(); } @Override public void run() { try { // 连接成功发送欢迎信息 welcoming(); // 登陆 login(); // 查词服务 String word = receive(); while(word != "#") { System.out.println(word); if (contains(word)) send(lookup(word)); else send(ServerMsg.NOT_FOUND_CODE); word = receive(); } }catch (IOException e){ e.printStackTrace(); }finally { try { sendBuffer.close(); recvBuffer.close(); connectionSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } } public static void main(String args[]) { // 初始化 init(); try{ // 创建监听套接字 ServerSocket serverSocket = new ServerSocket(8888); // 监听端口:“10000”,等待客户端发起连接,TCP状态:LISTEN // 连接套接字负责与客户端通信 while(true){ Socket connectionSocket = serverSocket.accept(); new Thread(new Worker(connectionSocket)).start(); } } catch (IOException e) { e.printStackTrace(); } } }
服务器端通信需要的核心对象:
ServerSocket “欢迎套接字”,监听连接建立请求,创建负责通信的“连接套接字”;
Socket (通过serverSocket.accept()获取)“连接套接字”,负责与客户端通信;
InputStream (通过connectionSocket.getInputStream()获取),字节输入流,其输入源为服务器端套接字的接收缓存;OutputStream (通过connectionSocket.getOutputStream()获取),字节输出流,其输出源为服务器端套接字的发送缓存;
2. 客户端代码
package com.gzn.client; import java.io.*; import java.net.InetSocketAddress; import java.net.Socket; import java.net.UnknownHostException; import java.util.Scanner; public class Main { private static class ClientMsg{ public static final String LOGIN_SUCCEED_CODE = "1001"; public static final String LOGIN_SUCCEED = "登陆成功,您现在可以使用查字服务了。"; public static final String LOGIN_FAIL = "登陆失败,用户名或者密码错误。"; public static final String NOT_FOUND_CODE = "2001"; public static final String NOT_FOUND = "对不起,您查找的汉字尚未收录本字典"; } private static final String hostname = "127.0.0.8"; private static final int port = 8888; private static final int requestTimeout = 60*1000; private static Socket clientSocket; private static BufferedReader recvBuffer; private static PrintWriter sendBuffer ; static { try { clientSocket = new Socket(); clientSocket.connect(new InetSocketAddress(hostname, port), requestTimeout); recvBuffer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(), "UTF-8")); sendBuffer = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream(), "UTF-8"), true); }catch (IOException e){ e.printStackTrace(); } } /** * 向套接字的发送缓存写入信息 * @throws IOException */ public static void send(String msg) throws IOException{ sendBuffer.println(msg); } /** * 从套接字的接收缓存读取信息 * @return * @throws IOException */ public static String receive() throws IOException{ return recvBuffer.readLine(); } public static void main(String[] args) { try{ // 欢迎信息 System.out.println(receive()); // 登陆信息 Scanner scanner = new Scanner(System.in); boolean flag = false; while(!flag){ System.out.println(receive()); String username = scanner.nextLine(); send(username); System.out.println(receive()); String password = scanner.nextLine(); send(password); String result = receive(); if(result.equals(ClientMsg.LOGIN_SUCCEED_CODE)){ System.out.println(ClientMsg.LOGIN_SUCCEED); flag = true; }else { System.out.println(ClientMsg.LOGIN_FAIL); } } // 查字 System.out.println("请输入您要查询的汉字:"); String word = scanner.nextLine(); while(!word.equals("#")){ if(word.length() != 1){ System.out.println("您的输入为空或者多于一个汉字!"); }else{ // 查词 send(word); String result = receive(); if (result.equals(ClientMsg.NOT_FOUND_CODE)){ System.out.println(ClientMsg.NOT_FOUND); }else{ System.out.println(result); } System.out.println("--------------------------------"); } System.out.println("请输入您要查询的汉字:"); word = scanner.nextLine(); } } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { System.out.println("欢迎下次使用!"); sendBuffer.close(); recvBuffer.close(); clientSocket.close(); }catch (IOException e){ e.printStackTrace(); } } } }
客户端核心对象(和服务器端差不多):
Socket (通过手动new)“客户套接字”,负责与客户端通信;
InputStream (通过clientSocket.getInputStream()获取),字节输入流,其输入源为服务器端套接字的接收缓存;OutputStream (通过clientSocket.getOutputStream()获取),字节输出流,其输出源为服务器端套接字的发送缓存;
-
C++实现简单Socket通信
2016-11-22 14:30:26C++实现简单Socket通信,最基本的代码。可以作为初始学习socket功能使用,仅供参考................... -
Socket 通信原理
2019-07-30 18:19:081. 客户端socket发送消息后,为什么服务端socket没有收到? 2. 使用while 循环实现连续输入,是不是就是多线程模式? 3. 对多线程处理机制不是很明白,希望详细讲解? 4. 希望详细讲解ServerSocketChannel和...整理和总结了一下大家常遇到的问题:
1. 客户端socket发送消息后,为什么服务端socket没有收到? 2. 使用while 循环实现连续输入,是不是就是多线程模式? 3. 对多线程处理机制不是很明白,希望详细讲解? 4. 希望详细讲解ServerSocketChannel和SocketChannel与ServerSoket和Socket的区别? 5. 希望有详细的例子,可以直接拷贝下来运行?
针对童鞋们提出的问题,我会在本文章中详细一一简答,并且给出详细的例子,下面言归正传。
一:socket通信基本原理。
首先socket 通信是基于TCP/IP 网络层上的一种传送方式,我们通常把TCP和UDP称为传输层。
如上图,在七个层级关系中,我们将的socket属于传输层,其中UDP是一种面向无连接的传输层协议。UDP不关心对端是否真正收到了传送过去的数据。如果需要检查对端是否收到分组数据包,或者对端是否连接到网络,则需要在应用程序中实现。UDP常用在分组数据较少或多播、广播通信以及视频通信等多媒体领域。在这里我们不进行详细讨论,这里主要讲解的是基于TCP/IP协议下的socket通信。
socket是基于应用服务与TCP/IP通信之间的一个抽象,他将TCP/IP协议里面复杂的通信逻辑进行分装,对用户来说,只要通过一组简单的API就可以实现网络的连接。借用网络上一组socket通信图给大家进行详细讲解:
首先,服务端初始化ServerSocket,然后对指定的端口进行绑定,接着对端口及进行监听,通过调用accept方法阻塞,此时,如果客户端有一个socket连接到服务端,那么服务端通过监听和accept方法可以与客户端进行连接。
二:socket通信基本示例:
在对socket通信基本原理明白后,那我们就写一个最简单的示例,展示童鞋们常遇到的第一个问题:客户端发送消息后,服务端无法收到消息。
服务端:
package socket.socket1.socket;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerSocketTest {
public static void main(String[] args) {
try {
// 初始化服务端socket并且绑定9999端口
ServerSocket serverSocket =new ServerSocket(9999); //等待客户端的连接 Socket socket = serverSocket.accept(); //获取输入流 BufferedReader bufferedReader =new BufferedReader(new InputStreamReader(socket.getInputStream())); //读取一行数据 String str = bufferedReader.readLine(); //输出打印 System.out.println(str); }catch (IOException e) {
e.printStackTrace();
}
}
}
客户端:
package socket.socket1.socket;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.Socket;
public class ClientSocket {
public static void main(String[] args) {
try {
Socket socket =new Socket(“127.0.0.1”,9999);
BufferedWriter bufferedWriter =new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); String str="你好,这是我的第一个socket"; bufferedWriter.write(str); }catch (IOException e) {
e.printStackTrace();
}
}
}
启动服务端:
发现正常,等待客户端的的连接
启动客户端:
发现客户端启动正常后,马上执行完后关闭。同时服务端控制台报错:
服务端控制台报错:
然后好多童鞋,就拷贝这个java.net.SocketException: Connection reset上王查异常,查询解决方案,搞了半天都不知道怎么回事。解决这个问题我们首先要明白,socket通信是阻塞的,他会在以下几个地方进行阻塞。第一个是accept方法,调用这个方法后,服务端一直阻塞在哪里,直到有客户端连接进来。第二个是read方法,调用read方法也会进行阻塞。通过上面的示例我们可以发现,该问题发生在read方法中。有朋友说是Client没有发送成功,其实不是的,我们可以通debug跟踪一下,发现客户端发送了,并且没有问题。而是发生在服务端中,当服务端调用read方法后,他一直阻塞在哪里,因为客户端没有给他一个标识,告诉是否消息发送完成,所以服务端还在一直等待接受客户端的数据,结果客户端此时已经关闭了,就是在服务端报错:java.net.SocketException: Connection reset
那么理解上面的原理后,我们就能明白,客户端发送完消息后,需要给服务端一个标识,告诉服务端,我已经发送完成了,服务端就可以将接受的消息打印出来。
通常大家会用以下方法进行进行结束:
socket.close() 或者调用socket.shutdownOutput();方法。调用这俩个方法,都会结束客户端socket。但是有本质的区别。socket.close() 将socket关闭连接,那边如果有服务端给客户端反馈信息,此时客户端是收不到的。而socket.shutdownOutput()是将输出流关闭,此时,如果服务端有信息返回,则客户端是可以正常接受的。现在我们将上面的客户端示例修改一下啊,增加一个标识告诉流已经输出完毕:
客户端2:
package socket.socket1.socket;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.Socket;
public class ClientSocket {
public static void main(String[] args) {
try {
Socket socket =new Socket(“127.0.0.1”,9999);
BufferedWriter bufferedWriter =new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); String str="你好,这是我的第一个socket"; bufferedWriter.write(str); //刷新输入流 bufferedWriter.flush(); //关闭socket的输出流 socket.shutdownOutput(); }catch (IOException e) {
e.printStackTrace();
}
}
}
在看服务端控制台:
服务端在接受到客户端关闭流的信息后,知道信息输入已经完毕,苏哦有就能正常读取到客户端传过来的数据。通过上面示例,我们可以基本了解socket通信原理,掌握了一些socket通信的基本api和方法,实际应用中,都是通过此处进行实现变通的。
三:while循环连续接受客户端信息:
上面的示例中scoket客户端和服务端固然可以通信,但是客户端每次发送信息后socket就需要关闭,下次如果需要发送信息,需要socket从新启动,这显然是无法适应生产环境的需要。比如在我们是实际应用中QQ,如果每次发送一条信息,就需要重新登陆QQ,我估计这程序不是给人设计的,那么如何让服务可以连续给服务端发送消息?下面我们通过while循环进行简单展示:
服务端:
package socket.socket1.socket;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerSocketTest {
public static void main(String[] args) {
try {
// 初始化服务端socket并且绑定9999端口
ServerSocket serverSocket =new ServerSocket(9999); //等待客户端的连接 Socket socket = serverSocket.accept(); //获取输入流,并且指定统一的编码格式 BufferedReader bufferedReader =new BufferedReader(new InputStreamReader(socket.getInputStream(),"UTF-8")); //读取一行数据 String str; //通过while循环不断读取信息, while ((str = bufferedReader.readLine())!=null){
//输出打印
System.out.println(str); }
}catch (IOException e) {
e.printStackTrace();
}
}
}
客户端:
package socket.socket1.socket;
import java.io.*;
import java.net.Socket;
public class ClientSocket {
public static void main(String[] args) {
try {
//初始化一个socket
Socket socket =new Socket("127.0.0.1",9999); //通过socket获取字符流 BufferedWriter bufferedWriter =new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); //通过标准输入流获取字符流 BufferedReader bufferedReader =new BufferedReader(new InputStreamReader(System.in,"UTF-8")); while (true){
String str = bufferedReader.readLine();
bufferedWriter.write(str); bufferedWriter.write("\n"); bufferedWriter.flush(); }
}catch (IOException e) {
e.printStackTrace();
}
}
}
客户端控制中心:
服务端控制中心:
大家可以看到,通过一个while 循环,就可以实现客户端不间断的通过标准输入流读取来的消息,发送给服务端。在这里有个细节,大家看到没有,我客户端没有写socket.close() 或者调用socket.shutdownOutput();服务端是如何知道客户端已经输入完成了?服务端接受数据的时候是如何判断客户端已经输入完成呢?这就是一个核心点,双方约定一个标识,当客户端发送一个标识给服务端时,表明客户端端已经完成一个数据的载入。而服务端在结束数据的时候,也通过这个标识进行判断,如果接受到这个标识,表明数据已经传入完成,那么服务端就可以将数据度入后显示出来。
在上面的示例中,客户端端在循环发送数据时候,每发送一行,添加一个换行标识“\n”标识,在告诉服务端我数据已经发送完成了。而服务端在读取客户数据时,通过while ((str = bufferedReader.readLine())!=null)去判断是否读到了流的结尾,负责服务端将会一直阻塞在哪里,等待客户端的输入。 通过while方式,我们可以实现多个客户端和服务端进行聊天。但是,下面敲黑板,划重点。由于socket通信是阻塞式的,假设我现在有A和B俩个客户端同时连接到服务端的上,当客户端A发送信息给服务端后,那么服务端将一直阻塞在A的客户端上,不同的通过while循环从A客户端读取信息,此时如果B给服务端发送信息时,将进入阻塞队列,直到A客户端发送完毕,并且退出后,B才可以和服务端进行通信。简单地说,我们现在实现的功能,虽然可以让客户端不间断的和服务端进行通信,与其说是一对一的功能,因为只有当客户端A关闭后,客户端B才可以真正和服务端进行通信,这显然不是我们想要的。 下面我们通过多线程的方式给大家实现正常人类的思维。
四:多线程下socket编程
服务端:
package socket.socket1.socket;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerSocketTest {
public static void main(String[] args)throws IOException {
// 初始化服务端socket并且绑定9999端口
ServerSocket serverSocket =new ServerSocket(9999); while (true){
//等待客户端的连接
Socket socket = serverSocket.accept(); //每当有一个客户端连接进来后,就启动一个单独的线程进行处理 new Thread(new Runnable() {
@Override
public void run() {
//获取输入流,并且指定统一的编码格式
BufferedReader bufferedReader =null; try {
bufferedReader =new BufferedReader(new InputStreamReader(socket.getInputStream(),“UTF-8”));
//读取一行数据 String str; //通过while循环不断读取信息, while ((str = bufferedReader.readLine())!=null){
//输出打印
System.out.println("客户端说:"+str); }
}catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
}
}
客户端:
package socket.socket1.socket;
import java.io.*;
import java.net.Socket;
public class ClientSocket {
public static void main(String[] args) {
try {
//初始化一个socket
Socket socket =new Socket("127.0.0.1",9999); //通过socket获取字符流 BufferedWriter bufferedWriter =new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); //通过标准输入流获取字符流 BufferedReader bufferedReader =new BufferedReader(new InputStreamReader(System.in,"UTF-8")); while (true){
String str = bufferedReader.readLine();
bufferedWriter.write(str); bufferedWriter.write("\n"); bufferedWriter.flush(); }
}catch (IOException e) {
e.printStackTrace();
}
}
}
通过客户端A控制台输入:
通过客户端B控制台输入:
服务端控制台:
通过这里我们可以发现,客户端A和客户端B同时连接到服务端后,都可以和服务端进行通信,也不会出现前面讲到使用while(true)时候客户端A连接时客户端B不能与服务端进行交互的情况。在这里我们看到,主要是通过服务端的 new Thread(new Runnable() {}实现的,每一个客户端连接进来后,服务端都会单独起个一线程,与客户端进行数据交互,这样就保证了每个客户端处理的数据是单独的,不会出现相互阻塞的情况,这样就基本是实现了QQ程序的基本聊天原理。
但是实际生产环境中,这种写法对于客户端连接少的的情况下是没有问题,但是如果有大批量的客户端连接进行,那我们服务端估计就要歇菜了。假如有上万个socket连接进来,服务端就是新建这么多进程,反正楼主是不敢想,而且socket 的回收机制又不是很及时,这么多线程被new 出来,就发送一句话,然后就没有然后了,导致服务端被大量的无用线程暂用,对性能是非常大的消耗,在实际生产过程中,我们可以通过线程池技术,保证线程的复用,下面请看改良后的服务端程序。
改良后的服务端:
package socket.socket1.socket;
import java.beans.Encoder;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ServerSocketTest {
public static void main(String[] args)throws IOException {
// 初始化服务端socket并且绑定9999端口
ServerSocket serverSocket =new ServerSocket(9999); //创建一个线程池 ExecutorService executorService = Executors.newFixedThreadPool(100); while (true) {
//等待客户端的连接
Socket socket = serverSocket.accept(); Runnable runnable = () -> {
BufferedReader bufferedReader =null;
try {
bufferedReader =new BufferedReader(new InputStreamReader(socket.getInputStream(), “UTF-8”));
//读取一行数据 String str; //通过while循环不断读取信息, while ((str = bufferedReader.readLine()) !=null) {
//输出打印
System.out.println("客户端说:" + str); }
}catch (IOException e) {
e.printStackTrace();
}
};
executorService.submit(runnable); }
}
}
运行后服务端控制台:
通过线程池技术,我们可以实现线程的复用。其实在这里executorService.submit在并发时,如果要求当前执行完毕的线程有返回结果时,这里面有一个大坑,在这里我就不一一详细说明,具体我在我的另一篇文章中《把多线程说个透》里面详细介绍。本章主要讲述socket相关内容。
在实际应用中,socket发送的数据并不是按照一行一行发送的,比如我们常见的报文,那么我们就不能要求每发送一次数据,都在增加一个“\n”标识,这是及其不专业的,在实际应用中,通过是采用数据长度+类型+数据的方式,在我们常接触的热Redis就是采用这种方式,
五:socket 指定长度发送数据
在实际应用中,网络的数据在TCP/IP协议下的socket都是采用数据流的方式进行发送,那么在发送过程中就要求我们将数据流转出字节进行发送,读取的过程中也是采用字节缓存的方式结束。那么问题就来了,在socket通信时候,我们大多数发送的数据都是不定长的,所有接受方也不知道此次数据发送有多长,因此无法精确地创建一个缓冲区(字节数组)用来接收,在不定长通讯中,通常使用的方式时每次默认读取8*1024长度的字节,若输入流中仍有数据,则再次读取,一直到输入流没有数据为止。但是如果发送数据过大时,发送方会对数据进行分包发送,这种情况下或导致接收方判断错误,误以为数据传输完成,因而接收不全。在这种情况下就会引出一些问题,诸如半包,粘包,分包等问题,为了后续一些例子中好理解,我在这里直接将半包,粘包,分包概念性东西在写一下(引用度娘)
5.1 半包
接受方没有接受到一个完整的包,只接受了部分。
原因:TCP为提高传输效率,将一个包分配的足够大,导致接受方并不能一次接受完。
影响:长连接和短连接中都会出现
5.2 粘包
发送方发送的多个包数据到接收方接收时粘成一个包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。
分类:一种是粘在一起的包都是完整的数据包,另一种情况是粘在一起的包有不完整的包
出现粘包现象的原因是多方面的:
1)发送方粘包:由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一包数据。若连续几次发送的数据都很少,通常TCP会根据优化算法把这些数据合成一包后一次发送出去,这样接收方就收到了粘包数据。
2)接收方粘包:接收方用户进程不及时接收数据,从而导致粘包现象。这是因为接收方先把收到的数据放在系统接收缓冲区,用户进程从该缓冲区取数据,若下一包数据到达时前一包数据尚未被用户进程取走,则下一包数据放到系统接收缓冲区时就接到前一包数据之后,而用户进程根据预先设定的缓冲区大小从系统接收缓冲区取数据,这样就一次取到了多包数据。
5.3分包
分包(1):在出现粘包的时候,我们的接收方要进行分包处理;
分包(2):一个数据包被分成了多次接收;
原因:1. IP分片传输导致的;2.传输过程中丢失部分包导致出现的半包;3.一个包可能被分成了两次传输,在取数据的时候,先取到了一部分(还可能与接收的缓冲区大小有关系)。
影响:粘包和分包在长连接中都会出现
那么如何解决半包和粘包的问题,就涉及一个一个数据发送如何标识结束的问题,通常有以下几种情况
固定长度:每次发送固定长度的数据;
特殊标示:以回车,换行作为特殊标示;获取到指定的标识时,说明包获取完整。
字节长度:包头+包长+包体的协议形式,当服务器端获取到指定的包长时才说明获取完整;
所以大部分情况下,双方使用socket通讯时都会约定一个定长头放在传输数据的最前端,用以标识数据体的长度,通常定长头有整型int,短整型short,字符串Strinng三种形式。
下面我们通过几个简单的小示例,演示发送接受定长数据,前面我们讲过通过特殊标识的方式,可是有什么我们发送的数据比较大,并且数据本身就会包含我们约定的特殊标识,那么我们在接受数据时,就会出现半包的情况,通过这种情况下,我们都是才有包头+包长+包体的协议模式,每次发送数据的时候,我们都会固定前4个字节为数据长度,那到数据长度后,我们就可以非常精确的创建一个数据缓存区用来接收数据。
那么下面就先通过包类型+包长度+消息内容定义一个socket通信对象,数据类型为byte类型,包长度为int类型,消息内容为byte类型。
首先我们创建府服务端socket。
package socket.socket1.socket5;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerSocketTest {
public static void main(String[] args) {
try {
ServerSocket serverSocket =new ServerSocket(9999);
Socket client = serverSocket.accept(); InputStream inputStream = client.getInputStream(); DataInputStream dataInputStream =new DataInputStream(inputStream); while (true){ byte b = dataInputStream.readByte(); int len = dataInputStream.readInt(); byte[] data =new byte[len -5]; dataInputStream.readFully(data); String str =new String(data); System.out.println("获取的数据类型为:"+b); System.out.println("获取的数据长度为:"+len); System.out.println("获取的数据内容为:"+str); }
}catch (IOException e) {
e.printStackTrace();
}
}
}
在服务端创建后,我们通过DataInputStream 数据流进行数据获取,首先我们获取数据的类型,然后在获取数据的长度,因为数据实际有效长度是整个数据的长度减去5,(包括前个字节为数据类型,前二到五个字节为数据长度)。然后根据数据的实际有效长度创建数据缓存区,用户存放数据,这边确保每次接接受数据的完整性,不会出现半包与粘包的情况。在数据读取的时候,我们通过readFully()方法读取数据。下面我们来创建socket的客户端:
package socket.socket1.socket5;
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
public class ClientSocketTest {
public static void main(String[] args) {
try {
Socket socket =new Socket(“127.0.0.1”,9999);
OutputStream outputStream = socket.getOutputStream(); DataOutputStream dataOutputStream =new DataOutputStream(outputStream); Scanner scanner =new Scanner(System.in); if(scanner.hasNext()){ String str = scanner.next(); int type =1; byte[] data = str.getBytes(); int len = data.length +5; dataOutputStream.writeByte(type); dataOutputStream.writeInt(len); dataOutputStream.write(data); dataOutputStream.flush(); }
}catch (IOException e) {
e.printStackTrace();
}
}
}
客户端socket创建后,我们通过dataOutputStream输出流中的writeByte()方法,设置数据类型,writeInt()方法设置数据长度,然后通过write()方法将数据发送到服务端进行通信,发送完毕后,为了确保数据完全发送,通过调用flush()方法刷新缓冲区。
下面我们通过控制可以看到服务端接受数据的情况:
客户端发送数据:
服务端接受数据:
上面服务端分别接受到数据的类型,长度和详细内容,具体下面的错误异常是由于客户端发送一次后关闭,服务端任在接受数据,就会出现连接重置的错误,这是一个简单的通过数据类型+数据长度+数据内容的方法发送数据的一个小例子,让大家了解socket通信数据发送的原理,在实际应用中,原理不出其左右,只是在业务逻辑上完善而已。
六:socket 建立长连接
在了解socket长连接和短连接之前,我们先通过一个概念性的东西,理解一下什么叫长连接,什么叫短连接,长连接的原理和短连接的原理,
6.1 长连接
指在一个连接上可以连续发送多个数据包,在连接保持期间,如果没有数据包发送,需要双方发链路检测包。整个通讯过程,客户端和服务端只用一个Socket对象,长期保持Socket的连接。
6.2 短连接
短连接服务是每次请求都建立链接,交互完之后关闭链接,
6.3 长连接与短连接的优势
长连接多用于操作频繁,点对点的通讯,而且连接数不能太多情况。每个TCP连接都需要三步握手,这需要时间,如果每个操作都是短连接,再操作的话那么处理速度会降低很多,所以每个操作完后都不断开,下次处理时直接发送数据包就OK了,不用建立TCP连接。例如:数据库的连接用长连接,如果用短连接频繁的通信会造成socket错误,而且频繁的socket 创建也是对资源的浪费。
而像WEB网站的http服务一般都用短链接,因为长连接对于服务端来说会耗费一定的资源,而像WEB网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源,如果用长连接,而且同时有成千上万的用户,如果每个用户都占用一个连接的话,那可想而知吧。所以并发量大,但每个用户无需频繁操作情况下需用短连好。(度娘)
在这章之前,你看到所有的例子,都是短连接,每次连接完毕后,都是自动断开,如果需要重新连接,则需要建立新的连接对象,比如像前一章我们看到的例子中,服务端有connection reset错误,就是短连接的一种。接下来,我们主要讲解一下长连接原理,在实际应用中,长连接他并不是真正意义上的长连接,(他不像我们打电话一样,电话通了之后一直不挂的这种连接)。他们是通过一种称之为心跳包或者叫做链路检测包,去定时检查socket 是否关闭,输入/输出流是否关闭。
在这里有个问题,也是好多初学者比较困惑的,也是好多初学socket时候,遇到的一个问题,那就是socket是通过流的方式通信的,既然关闭流,就是关闭socket,那么长连接不是很简单吗?就是我们读取流中的信息后,不关闭流,等下次使用时,直接往流中扔数据不就行了?
针对这个问题,我做个详细的解答,尽可能的描述清楚,首先我们socket是针对应用层与TCP/ip数据传输协议封装的一套方案,那么他的底层也是通过Tcp/Tcp/ip或则UDP通信的,所以说socket本身并不是一直通信协议,而是一套接口的封装。而tcp/IP协议组里面的应用层包括FTP、HTTP、TELNET、SMTP、DNS等协议,我们知道,http1.0是短连接,http1.1是长连接,我们在打开http通信协议里面在Response headers中可以看到这么一句Connection:keep-alive。他是干什么的,他就是表示长连接,但是他并不是一直保持的连接,他有一个时间段,如果我们想一直保持这个连接怎么办?那就是在制定的时间内让客户端和服务端进行一个请求,请求可以是服务端发起,也可以是客户端发起,通常我们是在客户端不定时的发送一个字节数据给服务端,这个就是我们称之为心跳包,想想心跳是怎么跳动的,是不是为了检测人活着,心会定时的跳动,就是这个原理。
喜欢这篇文章的可以点个赞,欢迎大家留言评论,记得关注我,每天持续更新技术干货、职场趣事、海量面试资料等等
如果你对java技术很感兴趣也可以加入我的java学习群(374308445)来交流学习,里面都是同行,群验证【CSDN2】有资源共享。
不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代 -
Socket通信实例
2017-05-11 10:02:07Socket通信实例。 -
socket通信过程
2021-02-28 14:14:47二、Socket通信 ---unix版 1、Socket通信流程 socket是"打开—读/写—关闭"模式的实现,以使用TCP协议通讯的socket为例,其交互流程大概如下: 服务器根据地址类型(ipv4,ipv6)、socket类型、协议创建socket 服务器...一、网络字节序与主机字节序
1、主机字节序:
就是自己的主机内部,内存中数据的保存顺序,可以分为两种:
小端字节序(little-endian):低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
大端字节序(big-endian):高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
2、网络字节序
大端字节序即网络字节序
3、数据传输过程
a的固有数据存储-------标准化--------转化成b的固有格式
II
a的主机字节序----------网络字节序 ---------b的主机字节序
标准化原因:不同的CPU有不同的字节序类型
二、Socket通信 ---unix版
1、Socket通信流程
socket是"打开—读/写—关闭"模式的实现,以使用TCP协议通讯的socket为例,其交互流程大概如下:
服务器根据地址类型(ipv4,ipv6)、socket类型、协议创建socket
服务器为socket绑定ip地址和端口号
服务器socket监听端口号请求,随时准备接收客户端发来的连接,这时候服务器的socket并没有被打开
客户端创建socket
客户端打开socket,根据服务器ip地址和端口号试图连接服务器socket
服务器socket接收到客户端socket请求,被动打开,开始接收客户端请求,直到客户端返回连接信息。这时候socket进入阻塞状态,所谓阻塞即accept()方法一直到客户端返回连接信息后才返回,开始接收下一个客户端谅解请求
客户端连接成功,向服务器发送连接状态信息
服务器accept方法返回,连接成功
客户端向socket写入信息
服务器读取信息
客户端关闭
服务器端关闭
2、三次握手建立连接
图示过程如下:
-
- 当客户端调用connect时,触发了连接请求,向服务器发送了SYN J包,这时connect进入阻塞状态;
- 服务器监听到连接请求,即收到SYN J包,调用accept函数接收请求向客户端发送SYN K ,ACK J+1,这时accept进入阻塞状态;
- 客户端收到服务器的SYN K ,ACK J+1之后,这时connect返回,并对SYN K进行确认;服务器收到ACK K+1时,accept返回,至此三次握手完毕,连接建立。
3、四次挥手断开连接
图示过程如下:
-
- 某个应用进程首先调用close主动关闭连接,这时TCP发送一个FIN M;
- 另一端接收到FIN M之后,执行被动关闭,对这个FIN进行确认。它的接收也作为文件结束符传递给应用进程,因为FIN的接收意味着应用进程在相应的连接上再也接收不到额外数据;
- 一段时间之后,接收到文件结束符的应用进程调用close关闭它的socket。这导致它的TCP也发送一个FIN N;
接收到这个FIN的源发送端TCP对它进行确认。
这样每个方向上都有一个FIN和ACK。
4、Socket通信主要函数信息
《---socket()、bind()、listen()、connect()、accept()、read()、write()、close()---》
socket函数 -- int socket(int domain, int type, int protocol)
参数解释:
- domain用于设置网络通信的域,函数socket()根据这个参数选择通信协议的族。通信协议族在文件sys/socket.h中定义。
可设置值:
名称
含义
名称
含义
PF_UNIX,PF_LOCAL
本地通信
PF_X25
ITU-T X25 / ISO-8208协议
AF_INET,PF_INET
IPv4 Internet协议
PF_AX25
Amateur radio AX.25
PF_INET6
IPv6 Internet协议
PF_ATMPVC
原始ATM PVC访问
PF_IPX
IPX-Novell协议
PF_APPLETALK
Appletalk
PF_NETLINK
内核用户界面设备
PF_PACKET
底层包访问
- type用于设置套接字通信的类型,主要有SOCKET_STREAM(流式套接字)、SOCK——DGRAM(数据包套接字)等。
可设置值:
名称
含义
SOCK_STREAM
Tcp连接,提供序列化的、可靠的、双向连接的字节流。支持带外数据传输
SOCK_DGRAM
支持UDP连接(无连接状态的消息)
SOCK_SEQPACKET
序列化包,提供一个序列化的、可靠的、双向的基本连接的数据传输通道,数据长度定常。每次调用读系统调用时数据需要将全部数据读出
SOCK_RAW
RAW类型,提供原始网络协议访问
SOCK_RDM
提供可靠的数据报文,不过可能数据会有乱序
SOCK_PACKET
这是一个专用类型,不能呢过在通用程序中使用
注:并不是所有的协议族都实现了这些协议类型,例如,AF_INET协议族就没有实现SOCK_SEQPACKET协议类型。
-
-
Android Socket通信简单实现
2021-09-24 15:08:30公司要实现一个简单的聊天功能,提前研究一下Socket通信,而公司的服务端功能又没有实现,所以这里就把服务端的功能放到一个界面实现了。 直接上代码: <?xml version="1.0" encoding="utf-8"?> <... -
socket通信简述
2021-08-26 16:52:04对TCP/IP、UDP、Socket编程这些词你不会很陌生吧?随着网络技术的发展,这些词充斥着我们的耳朵。那么我想问: 1.什么是TCP/IP、UDP? 2.Socket在哪里呢? 3.Socket是什么呢? 4.你会使用它们吗?什么是TCP/IP、UDP... -
linux下的socket通信
2020-11-13 10:48:13linux下的socket通信 在linux下,无论多么复杂的服务器或客户端程序,无论什么编程语言实现的,其底层都离不开linux内核提供的系统调用(也就十多个函数),其网络通信的基本流程一定如下所述: 对于服务器,其通信... -
unity socket通信
2022-02-15 15:03:54同一局域网下Socket才能通信 首先判断两个电脑是否在同一个局域网下 使两个电脑处在同一个局域网下 1.服务端与客户端代码 服务器端:在VS创建一个空的C#项目NetworkServer using System; using System.Collections.... -
Socket通信(以C#为例)
2020-11-01 16:43:153、Socket通信的基本原理 4、Socket应用示例 正文: 1、为什么要用Socket? 我们深谙信息交流的价值,网络中进程之间是如何通信,我们每天打开浏览器浏览网页时,浏览器的进程怎么与web服务器通信的?当你用QQ... -
C++ socket通信详解
2020-08-28 22:07:51Socket是什么 ...这里我把TCP服务器比作政府某一服务部门能,TCP客户端比作企业中某一部门电话,描述这一过程,恰好就像是socket通信,服务部门提供服务,企业部门申请服务。 要实现通信,首先政府 -
socket通信原理-TCP
2022-03-03 10:35:37socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用以实现进程在网络中通信。 socket如何实现通信 第一次握手: 客户端 A.调用socket()函数,创建socket描述符 ... -
Android studio开发——同一台设备上实现socket通信
2022-01-10 16:49:08Android studio开发——同一台设备上实现socket通信 -
C#和Python的Socket通信
2020-02-21 00:09:17在控制过程中,需要使用socket通信将python处理后的数据发送到unity环境中。 2.Socket通信 Socket封装了TCP/IP协议,可以视为TCP/IP协议向程序员开发所提供的接口,从而简化了网络编程。Socket在网络通信中的位置... -
socket通信(C#)
2021-09-26 21:56:14通信两端分别为客户端(Client)和服务器(Server): 统一编码格式:【Encoding.UTF8】 测试环境: 需要启动谁就将谁设为启动项: (先启动Server,后启动Client) 服务器(Server): 1:建立一个Socket对像; 2... -
Socket通信原理(多线程)
2021-05-31 20:19:50而发送和接收请求都是基于Socket 对象实现的。而这个过程是怎么样的呢?(这里介绍的是基于TCP/IP 的通信) 下面我先用一个简单的图解表示一下: 通过上面的图解,我们可以很清晰的看到整个通信的流程。 对于编码来... -
【网络编程知识】使用Socket通信,做一个简单的多人聊天室
2022-03-04 17:44:35正好最近在看一些Socket套接字的内容,就想着能不能使用Socket做一个简单的通信功能,来加深对Socket的认知。 所以这篇文章就来使用Socket来简单制作一个多人聊天室,看看Socket到底怎样进行使用。 -
使用Java完成Socket通信
2022-04-18 20:34:05用Java实现一个最基本的Socket_TCP编程 可以放在一个项目中,创建两个Java文件 注意:先运行服务器端(SocketTCP_Server类) 再运行客户端(SocketTCP_Client类) import java.io.InputStream; import java... -
C#Socket通信实例
2010-11-25 11:43:28此资源是一款WinFrom程序,客户端与服务器端互发数据 -
QT的Socket通信
2021-04-09 11:19:43一、linux下的tcp通信过程 其中bind绑定,会固定一个端口,否则是随机的。 一个链接是由双方的ip和端口组成的,固定端口保证源的不变性, ...Qt中常用的用于socket通信的套接字类: QTcpServer 用于TCP/IP通信, ... -
Socket通信实现多人聊天应用
2016-05-25 09:41:43套接字(socket)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机... -
Socket通信原理
2019-06-12 21:29:24Socket通信原理 对TCP/IP、UDP、Socket编程这些词你不会很陌生吧?随着网络技术的发展,这些词充斥着我们的耳朵。那么我想问: 什么是TCP/IP、UDP? Socket在哪里呢? Socket是什么呢? 你会使用它们... -
什么是SOCKET通信,看完马上明白
2022-01-12 10:57:31Socket是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议、本地主机的IP地址、本地进程的协议端口、远程主机的IP地 -
c#Socket通信实例
2021-12-27 14:03:27一、Socket通信简介 1.按惯例先来介绍下socket Windows中的很多东西都是从Unix领域借鉴过来的,Socket也是一样。在Unix中,socket代表了一种文件描述符(在Unix中一切都是以文件为单位),而这里这个描述符则是... -
Java c++ socket通信
2016-03-20 21:40:03Java客户端,c++服务端通过socket进行网络通信,传输数据