Socket

C (win) - Android

섭섭입니다 2020. 3. 2. 01:53

소켓통신 이용하여 "hello world" 문자열 보내보기

 

기존 C언어로 구성했던  window 환경에서 C-C 간의 채팅 소켓통신을 했던 C서버를 이용하고, python - android 에서 이용했던  android 클라이언를 이용하여 문자열, 문자, 숫자 이러한 것들을 클라이언트에서 window 에게 간단히 보낼 수 있는 (Client인 안드로이드에서는 서버가 보낸 메시지를 확인할 수 없음 코드변경 필요.) 것을 성공했다!

 

 

우선 C언어의 코드이다. 내 생각이지만 기본 C언어 서버로도 충분히 가능할 것 같다. recv하는 함수를 넣어주면 말이다. 하지만 기본에서는 recv 하는 함수 대신 send 하기 때문에 기본에서는 연결만 되고 끊기지 않나 생각이 든다.

 

그래서 recv 기능도 가능한 채팅 코드를 이용하였다.

 

 

 < C SERVER >

 

#pragma comment(lib, "ws2_32.lib")
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>

#define BUFSIZE 1024

void ErrorHandling(char* message);

int main(int argc, char** argv) {

    WSADATA wsaData;
    SOCKET servSock, clntSock;   //SOCKET은 사실 UINT_PTR 형이다.
    SOCKADDR_IN servAddr, clntAddr;

    char message[BUFSIZE]; //Message Buffer
    int strLen;
    int fromLen, nRcv;

    if (argc != 2) {
        printf("Please, Insert Port Number\n");
        exit(1);
    }

    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
        ErrorHandling("Load WinSock 2.2 DLL Error");

    servSock = socket(PF_INET, SOCK_STREAM, 0);
    if (servSock == INVALID_SOCKET)
        ErrorHandling("Socket Error");

    memset(&servAddr, 0, sizeof(SOCKADDR_IN));
    servAddr.sin_family = AF_INET;
    servAddr.sin_port = htons(atoi(argv[1]));
    servAddr.sin_addr.s_addr = htonl(INADDR_ANY);

    if (bind(servSock, (void*)&servAddr, sizeof(servAddr)) == SOCKET_ERROR)
        ErrorHandling("Bind Error");

    if (listen(servSock, 2) == SOCKET_ERROR)
        ErrorHandling("Listen Error");

    fromLen = sizeof(clntAddr);

    clntSock = accept(servSock, (void*)&clntAddr, &fromLen);
    if (clntSock == INVALID_SOCKET) {
        ErrorHandling("Accept Error");
    }
    else {
        printf("%s Connection Complete!\n", inet_ntoa(clntAddr.sin_addr));
        printf("Start ...\n");
    }

    closesocket(servSock);

    while (1) {
        printf("Message Receives ...\n");
        nRcv = recv(clntSock, message, sizeof(message) - 1, 0);

        if (nRcv == SOCKET_ERROR) {
            printf("Receive Error..\n");
            break;
        }
        message[nRcv] = '\0';

        if (strcmp(message, "exit") == 0) {
            printf("Close Clinet Connection..\n");
            break;
        }

        printf("Receive Message : %s", message);
        printf("\nSend Message : ");
        gets(message);
        if (strcmp(message, "exit") == 0) {
            send(clntSock, message, (int)strlen(message), 0);
            break;
        }

        send(clntSock, message, (int)strlen(message), 0);
    }

    closesocket(clntSock);
    WSACleanup();

    printf("Close Connection..\n");
    _getch();

    return 0;
}

void ErrorHandling(char* message) {
    WSACleanup();
    fputs(message, stderr);
    fputc('\n', stderr);
    _getch();
    exit(1);
}

 

 < Android CLIENT >

 

 

 [activity_main.xml]

 

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/TextView01"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        tools:ignore="MissingConstraints" />

    <EditText
        android:id="@+id/EditText01"
        android:layout_width="289dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="92dp"
        app:layout_constraintStart_toStartOf="@+id/Button01"
        tools:layout_editor_absoluteY="0dp"
        tools:ignore="MissingConstraints"
        android:layout_marginLeft="92dp" />

    <Button
        android:id="@+id/Button01"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Send"
        tools:ignore="MissingConstraints" />

    <Button
        android:id="@+id/button02"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="16dp"
        android:layout_marginTop="456dp"
        android:text="Connect"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginRight="16dp" />

    <TextView
        android:id="@+id/chatTV"
        android:layout_width="fill_parent"
        android:layout_height="381dp"
        android:layout_marginTop="64dp"
        app:layout_constraintTop_toTopOf="@+id/TextView01"
        tools:layout_editor_absoluteX="0dp"
        tools:ignore="MissingConstraints" />

</androidx.constraintlayout.widget.ConstraintLayout>

 

 

 

[ MainActivity.java ]

 

package com.example.python_android_ex2;

import android.os.Handler;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;


public class MainActivity extends AppCompatActivity {

    private Handler mHandler;
    Socket socket;
    private String ip = "210.210.237.133"; // IP 주소
    private int port = 8080; // PORT번호
    EditText et;
    TextView msgTV;

    @Override
    protected void onStop() {
        super.onStop();
        try {
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mHandler = new Handler();

        et = (EditText) findViewById(R.id.EditText01);
        Button btn = (Button) findViewById(R.id.Button01);
        Button btnCon = (Button)findViewById(R.id.button02);
        final TextView tv = (TextView) findViewById(R.id.TextView01);
        msgTV = (TextView)findViewById(R.id.chatTV);

        btn.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                if (et.getText().toString() != null || !et.getText().toString().equals("")) {
                    ConnectThread th =new ConnectThread();
                    th.start();
                }
            }
        });
    }

    class ConnectThread extends Thread{
        public void run(){
            try{
                //소켓 생성
                InetAddress serverAddr = InetAddress.getByName(ip);
                socket =  new Socket(serverAddr,port);
                //입력 메시지
                String sndMsg = et.getText().toString();
                Log.d("=============", sndMsg);
                //데이터 전송
                PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true);
                out.println(sndMsg);
                //데이터 수신
                BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String read = input.readLine();
                //화면 출력
                mHandler.post(new msgUpdate(read));
                Log.d("=============", read);
                socket.close();
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }
    // 받은 메시지 출력
    class msgUpdate implements Runnable {
        private String msg;
        public msgUpdate(String str) {
            this.msg = str;
        }
        public void run() {
            msgTV.setText(msgTV.getText().toString() + msg + "\n");
        }
    };
}

 

 

[ AndroidManifest.xml ]

 

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.python_android_ex2">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

 

 

 

 

안드로에서 위와 같이 hello 라고 보내면 서버 쪽에서 메시지를 확인할 수 있다.

 

 

아래와 같이 서버를 열고 안드로이드에서 접속하여 메시지를 보내면 접속이 되었다고 뜨며 보내진 메시지를 볼 수 있다.

 

win 에서 보낸 메시지는 안드로이드에서 확인할 수 없다. 접속 확인 정도는 다른 어플인 AndroidPython 에서 로그에서 확인 가능하다. 하지만 여기서도 서버에서 보낸 메시지는 볼 수 없다.