LoginSignup
18

More than 5 years have passed since last update.

iOSとWindowsのソケット通信

Last updated at Posted at 2017-08-19

この記事の目的

iOS-Windows間ソケット通信の基礎的なコードをメモ

前提

クライアント: iOS (Swift3)
サーバー: Windows (C#)

参考

SwiftでTCP/IP通信
Apple Developer Forums
Apple Developer Documentation

サーバー側

以下は、SwiftでTCP/IP通信 のC#をほぼそのまま拝借したものです。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyServer
{
    class Program
    {
        static void Main(string[] args)
        {
            //ListenするIPアドレスを決める
            string host = "localhost";
            System.Net.IPAddress ipAdd
                = System.Net.Dns.GetHostEntry(host).AddressList[0];
            Console.WriteLine("ListenするIPアドレス: " + ipAdd);

            //Listenするポート番号
            int port = xxxx;

            //TcpListenerオブジェクトの生成
            System.Net.Sockets.TcpListener listener
                = new System.Net.Sockets.TcpListener(System.Net.IPAddress.Any, port);

            //Listenを開始する
            listener.Start();
            Console.WriteLine("Listenを開始しました({0}:{1})。",
                ((System.Net.IPEndPoint)listener.LocalEndpoint).Address,
                ((System.Net.IPEndPoint)listener.LocalEndpoint).Port);

            //接続要求があったら受け入れる
            System.Net.Sockets.TcpClient client = listener.AcceptTcpClient();
            Console.WriteLine("クライアント({0}:{1})と接続しました。",
                ((System.Net.IPEndPoint)client.Client.RemoteEndPoint).Address,
                ((System.Net.IPEndPoint)client.Client.RemoteEndPoint).Port);

            //NetworkStream取得
            System.Net.Sockets.NetworkStream ns = client.GetStream();

            //クライアントから送られたデータを受信する
            System.Text.Encoding enc = System.Text.Encoding.UTF8;
            bool is_connected = true;
            string resMsg;
            while (true)
            {
                is_connected = true;
                System.IO.MemoryStream ms = new System.IO.MemoryStream();
                byte[] resBytes = new byte[256];
                do
                {
                    //データの一部を受信する
                    int resSize = ns.Read(resBytes, 0, resBytes.Length);
                    //Readが0を返した時はクライアントが接続したと判断
                    if (resSize == 0)
                    {
                        is_connected = false;
                        Console.WriteLine("クライアントが切断しました。");
                        break;
                    }
                    //受信したデータを蓄積する
                    ms.Write(resBytes, 0, resSize);
                } while (ns.DataAvailable);
                //受信したデータを文字列に変換
                resMsg = enc.GetString(ms.ToArray());
                ms.Close();
                Console.WriteLine("受信メッセ―ジ: " + resMsg);
                if (resMsg.Contains("end"))
                {
                    break;
                }
            }

            if (is_connected)
            {
                //クライアントにデータを送信する
                //クライアントに送信する文字列を作成
                string sendMsg = resMsg.ToString();
                //文字列をByte型配列に置換
                byte[] sendBytes = enc.GetBytes(sendMsg);
                //データを送信する
                ns.Write(sendBytes, 0, sendBytes.Length);
                Console.WriteLine("送信メッセージ: " +  sendMsg);
            }

            //閉じる
            ns.Close();
            client.Close();
            Console.WriteLine("クライアントとの接続を閉じました。");

            //リスナを閉じる
            listener.Stop();
            Console.WriteLine("Listenerを閉じました。");

            Console.ReadLine();
        }
    }
}

クライアント側

以下は、先ほどのブログをSwift3に書き改めさせていただいたものです。

import UIKit

class ViewController: UIViewController {

    var Connection1 = Connection()

    @IBOutlet weak var TB_SendCommand: UITextField!

    @IBAction func BT_Connect(sendr: AnyObject){
        Connection1.connect()
    }

    @IBAction func BT_Send(sendr: AnyObject){
        //テキストの文字を取得してsendCommand()を行う
        let sendtext = TB_SendCommand.text
        if ((sendtext! as NSString).length > 0) {
            Connection1.sendCommand(command: sendtext!)
        }
    }

    @IBAction func BT_End(sendr: AnyObject){
        Connection1.sendCommand(command: "end")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

class Connection: NSObject, StreamDelegate {
    let ServerAddress: CFString =  NSString(string: "xxx.xxx.xxx.xxx") //IPアドレスを指定
    let serverPort: UInt32 = xxxx //開放するポートを指定

    private var inputStream : InputStream!
    private var outputStream: OutputStream!

    //**
    /* @brief サーバーとの接続を確立する
     */
    func connect(){
        print("connecting.....")

        var readStream : Unmanaged<CFReadStream>?
        var writeStream: Unmanaged<CFWriteStream>?

        CFStreamCreatePairWithSocketToHost(nil, self.ServerAddress, self.serverPort, &readStream, &writeStream)

        self.inputStream  = readStream!.takeRetainedValue()
        self.outputStream = writeStream!.takeRetainedValue()

        self.inputStream.delegate  = self
        self.outputStream.delegate = self

        self.inputStream.schedule(in: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode)
        self.outputStream.schedule(in: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode)

        self.inputStream.open()
        self.outputStream.open()

        print("connect success!!")
    }

    //**
    /* @brief inputStream/outputStreamに何かしらのイベントが起きたら起動してくれる関数
     *        今回の場合では、同期型なのでoutputStreamの時しか起動してくれない
     */
    func stream(_ stream:Stream, handle eventCode : Stream.Event){
        //print(stream)
    }

    //**
    /* @brief サーバーにコマンド文字列を送信する関数
     */
    func sendCommand(command: String){
        var ccommand = command.data(using: String.Encoding.utf8, allowLossyConversion: false)!
        let text = ccommand.withUnsafeMutableBytes{ bytes in return String(bytesNoCopy: bytes, length: ccommand.count, encoding: String.Encoding.utf8, freeWhenDone: false)!}
        self.outputStream.write(UnsafePointer(text), maxLength: text.utf8.count)
        print("Send: \(command)")

        //"end"を受信したら接続切断
        if (String(describing: command) == "end") {
            self.outputStream.close()
            self.outputStream.remove(from: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode)

            while(!inputStream.hasBytesAvailable){}
            let bufferSize = 1024
            var buffer = Array<UInt8>(repeating: 0, count: bufferSize)
            let bytesRead = inputStream.read(&buffer, maxLength: bufferSize)
            if (bytesRead >= 0) {
                let read = String(bytes: buffer, encoding: String.Encoding.utf8)!
                print("Receive: \(read)")
            }
            self.inputStream.close()
            self.inputStream.remove(from: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode)
        }
    }

}

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18