A kotlin multiplatform library that allows you send network data via sockets
Report Bug
ยท
Request Feature
Table of Contents
Managing network calls can be slightly different based on each platform. This project aims to make it easier to manage sockets in a cross platform way using kotlin multiplatform. This was originally created as a side project for a kotlin multiplatform mqtt data sync solution.
Platform | ๐ Builds๐ + ๐ฌTests๐ฌ | Native Wrapper For |
---|---|---|
JVM 1.8 |
๐ | AsynchronousSocketChannel |
Node.js |
๐ | Socket |
Browser (Chrome) |
๐ | unavailable |
Android |
๐ | AsynchronousSocketChannel falling back to SocketChannel |
iOS |
๐ | Custom wrapped NWConnection |
WatchOS |
๐ | Custom wrapped NWConnection |
TvOS |
๐ | Custom wrapped NWConnection |
MacOS |
๐ | Custom wrapped NWConnection |
Linux X64 |
๐ฎ | WIP |
Windows X64 |
๐ฎ | WIP |
- Add
implementation("com.ditchoom:socket:$version")
to yourbuild.gradle
dependencies - Copy the contents of this patch.js file into
your own
webpack.config.d
directory if you are targetingjs
- Add this to your
kotlin {
bracket in build.gradle.kts if you are targeting an apple platform
kotlin {
...
cocoapods {
ios.deploymentTarget = "13.0"
osx.deploymentTarget = "11.0"
watchos.deploymentTarget = "6.0"
tvos.deploymentTarget = "13.0"
pod("SocketWrapper") {
source = git("https://github.com/DitchOoM/apple-socket-wrapper.git") {
tag = "0.1.3"
}
}
}
}
// Run in a coroutine scope
val socket = ClientSocket.connect(
port = 80, // no default
hostname = "example.com", // null is default which points to localhost
timeout = 15.seconds, // default
socketOptions = null, // default
)
val isOpen = socket.isOpen()
val localPort = socket.localPort()
val remotePort = socket.remotePort()
val stringRead = socket.readString() // read a string. utf8 is the default
val readBuffer =
socket.read() // read a ReadBuffer as defined in the buffer module. call resetForRead() before consumption
socket.readFlow().collect { buffer -> // default charset is utf8
buffer.resetForRead()
// buffer is ready for consumption
}
socket.readFlowString().collect { value -> // default charset is utf8
// read a string
}
val bytesWritten = socket.write(buffer) // write the buffer to the socket
val bytesWrittenString = socket.writeString("hello") // write the buffer to the socket. utf8 is default
socket.close() // close the socket
Or use lambda which auto closes the socket
// Run in a suspend method, same defaults as the other `connect` method
val response = ClientSocket.connect(80, hostname = "example.com") { socket ->
val request =
"""
GET / HTTP/1.1
Host: example.com
Connection: close
"""
val bytesWritten = socket.write(request)
socket.read() // can throw a SocketClosedException
}
// response is populated, no need to call socket.close()
val server = ServerSocket.allocate()
val acceptedClientFlow = server.bind()
val isListening: Boolean = server.isListening() // returns true if server is listening for connections
val listenPort: Int = server.port() // the assigned port, -1 if unassigned or closed
launch {
acceptedClientFlow.collect { serverToClient ->
// new client has connected, can now read and write to it.
// same api as ClientSocket
val localPort = serverToClient.localPort()
val remotePort = serverToClient.remotePort()
val stringRead = serverToClient.readString() // read a string. utf8 is the default
val readBuffer =
serverToClient.read() // read a ReadBuffer as defined in the buffer module. call resetForRead() before consumption
serverToClient.readFlow().collect { buffer -> // default charset is utf8
buffer.resetForRead()
// buffer is ready for consumption
}
serverToClient.readFlowString().collect { value -> // default charset is utf8
// read a string
}
val bytesWritten = serverToClient.write(buffer) // write the buffer to the socket
val bytesWrittenString = serverToClient.writeString("hello") // write the buffer to the socket. utf8 is default
serverToClient.close() // close the socket
}
}
server.close() // stops listening for connections on the assigned port
// Simply add tls=true to your ClientSocket.connect or ClientSocket.allocate
val response = ClientSocket.connect(port, hostname, tls = true) { socket ->
// do something
}
Refer to SimpleSocketTests.kt for a tested example
val server = ServerSocket.allocate()
val text = "Sphinx of black quartz, judge my vow."
val acceptedClientFlow = server.bind()
launch {
acceptedClientFlow.collect { serverToClient ->
val dataReceivedFromClient = serverToClient.readString()
serverToClient.writeString(dataReceivedFromClient)
serverToClient.close()
}
}
val clientToServer = ClientSocket.allocate()
clientToServer.open(server.port())
clientToServer.writeString(text)
assertEquals(text, clientToServer.readString())
clientToServer.close()
server.close()
Refer to SimpleSocketTests.kt for a tested example
val server = ServerSocket.allocate()
val text = "yolo swag lyfestyle"
val acceptedClientFlow = server.bind()
launch {
acceptedClientFlow.collect { serverToClient ->
serverToClient.writeString(text)
assertEquals(text, serverToClient.readString())
serverToClient.close()
}
}
ClientSocket.connect(server.port()) { clientToServer ->
assertEquals(text, clientToServer.readString())
clientToServer.writeString(text)
clientToServer.close()
}
server.close()
git clone git@github.com:DitchOoM/socket.git
- Open cloned directory with Intellij IDEA.
- Be sure to open with gradle
See the open issues for a list of proposed features ( and known issues).
Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are greatly appreciated.
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature
) - Commit your Changes (
git commit -m 'Add some AmazingFeature'
) - Push to the Branch (
git push origin feature/AmazingFeature
) - Open a Pull Request
Distributed under the Apache 2.0 License. See LICENSE
for more information.