I am currently trying to create a simple TCP Peer2Peer communication between two computers via Swift. On my on computer it works fine, but when I move one instance to another computer, it receives messages on the second PC but is not able to send any messages.
I have disabled my Firewall and tried it with a Hotspot on my phone. When I use my Rust Peer2Peer connector, it totally works in any case.
What am I doing wrong?
Here is my full code
P2P.swift
import Foundation
import SocketSwift
class P2P {
var reciever: Reciever?
var sender: Sender?
init(serverPort: Int, otherIp: String, otherPort: Int, ownIp: String) {
print("Data: \(ownIp):\(serverPort) -> \(otherIp):\(otherPort)")
_ = Task {
sender = Sender(serverPort: serverPort, ownIp: ownIp)
sender?.acceptClient()
while(true) {
do {
try sender?.writeStream(message: readLine() ?? "No")
} catch let error {
print("Error while sending Data \(error)")
}
}
}
self.reciever = Reciever(otherIp: otherIp, otherPort: otherPort)
while(true){ //programm
}
}
}
Reciever.swift
import Foundation
import SocketSwift
class Reciever { //AKA Client for RECIEVING MESSAGES
let prefix = "RECIEVER: "
var client: Socket? = nil //on this channel I will recieve data
init(otherIp: String, otherPort: Int) {
_ = clientConnectAsync(otherPort: otherPort, otherIp: otherIp)
while(true) {
do {
print(try readStreamAsync(size: 10) ?? "Nothing to read")
} catch let error {
print(prefix + "Error while reading \(error)")
}
}
}
//read whats in the incoming pip and retuns a string. takes the size of how many input it should take
private func readStreamAsync(size: Int) throws -> String? {
var buffer = [UInt8](repeating: 0, count: size) // allocate buffer
var result: String = "";
_ = try client?.read(&buffer, size: size) // throws the data into the buffer var
var isEmpty: Bool = true
for i in 0...size-1 {
if buffer[i] != 0 {
isEmpty = false
}else {
break
}
result.append(String(Character(Unicode.Scalar(buffer[i]))))
}
buffer.removeAll()
if isEmpty {
return nil
}
return result
}
func clientConnectAsync(otherPort: Int, otherIp: String) -> Bool {
do { //TODO async retry to connect to other
client = try Socket(.inet, type: .stream, protocol: .tcp) // create client for sending data
//try client?.connect(address: SocketAddress(port: Port(otherPort), address: otherIp)) // start trying to connect to p2p other server
//try to connect to server
print(prefix + " Tries to connect to other peer")
try client?.connect(port: Port(otherPort), address: otherIp)
print(prefix + "Reciever could connect to the other peer. Now able to retrieve MSG")
return true
} catch {
print(prefix + "Client could not connect to other server: \(error)") //print the reason why the connection was not successful
}
client?.close() // client did not connect. Close pipe!!
do {
Thread.sleep(forTimeInterval: 1)
//try await Task.sleep(nanoseconds: UInt64(0.5/*SECOND(S)*/ * Double(NSEC_PER_SEC))) //waites for X sec bec otherwise the console would be flooded
} catch {
print("Error sleeping \(error)")
}
return clientConnectAsync(otherPort: otherPort, otherIp: otherIp) //retry bec no connection could be etablished
}
}
Sender.swift
import Foundation
import SocketSwift
class Sender { //AKA SERVER for SENDING messages (I know its confusing)
var server: Socket? = nil //on this channel I will accept connections
var send: Socket?
init(serverPort: Int, ownIp: String) {
do {
server = try Socket(.inet, type: .stream, protocol: .tcp) //Initialize Server, this is running all time.
try server?.set(option: .reuseAddress, true) // set SO_REUSEADDR to 1
try server?.bind(port: Port(serverPort), address: ownIp) // bind 'ownIpt:serverPort'
try server?.listen() // allow incoming connections
print("Server on port \(serverPort)")
} catch {
print("Server creation failed: \(error)")
return
}
}
//Send message
public func writeStream(message: String) throws {
if send == nil {
return
}
let inputSt: [UInt8] = ([UInt8])(message.utf8)
do {
try send?.write(inputSt)
} catch let error {
print("Error while sending message \(error)")
}
print("Message: \(message) should be printed")
}
func acceptClient() -> Socket? {
do {
print("trying to accept Peerconnection")
send = try server?.accept()
print("PEER connected to this server. Now able to send MSG")
} catch {
print("Error fetching connection \(error)")
return nil
}
if send == nil {
print("Peer failed to connected")
return nil
} else {
//print("Someone connected \(String(describing:send.))")
/*if send?.fileDescriptor == 5 {
print("Du kannst nur empfangen")
//send = try server?.accept()
}else {
print("Du kannst nur senden")
}
print("Someone connected \(String(describing: send?.fileDescriptor))")*/
return send
}
}
}
while true { }being the extreme example) is an antipattern. That’s just going to block the current thread. Anything that spins constantly should be scrupulously avoided. Generally, we’d want to shift to event-driven patterns. And, nowadays, we would want to use Swift concurrency patterns.