Linux上のホストとWindows上のクライアントがSocket通信するサンプル
LINUXは、RedHut6.2J使用。ほかのLINUXでは動作するかどうか不明。
もしほかのLINUXで動作確認した場合はメールをいただけると超幸運です。
LINUX側のサーバ 以下は、RedHut6.2Jのソケットサンプルの動作確認したもの
コンパイルは、 gcc server.c
/*
* iserver2.c
* クライアントからの接続要求を受け付けるサーバープログラム。
* STREAM型のソケットを使う。
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h> /* #include の代わり */
#define MAX_NAME_LEN 64
#define MAX_PASS_LEN 16 // for PayIn 2000/11/1
#define MAX_MSG_LEN 128 // for PayIn
typedef struct pk_sign_in
{
char name[MAX_NAME_LEN];
char pass[MAX_PASS_LEN];
}pksignin;
//-----------------------------------
// PayIn サインインリザルトパケット-
// 2000/10/18 -
//-----------------------------------
typedef struct pk_sign_in_result
{
int ans; //==1 : OK, ==0 : NG, 0 : ERROR
char msg[MAX_MSG_LEN];
}pkresult;
#define PORT 9005
main()
{
int i;
int fd1, fd2;
struct sockaddr_in saddr;
struct sockaddr_in caddr;
int len;
int ret;
char buf[1024];
int pid;
int msglen;
int opt;
char* te="recieved OK"; // kekka henshin you mojiretu
/*
* ソケットを作る。このソケットはUNIXドメインで、ストリーム型ソケット。
*/
if ((fd1 = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
exit(1);
}
opt=1;
if(setsockopt(fd1,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(int))!=0){
perror("setsockopt");
exit(-1);
}
fprintf(stderr,"socket:OK\n");
/*
* saddrの中身を0にしておかないと、bind()でエラーが起こることがある
*/
bzero((char *)&saddr, sizeof(saddr));
/*
* ソケットの名前を入れておく
*/
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = INADDR_ANY;
saddr.sin_port = htons(PORT);
/*
* ソケットにアドレスをバインドする。
*/
if (bind(fd1, (struct sockaddr *)&saddr, sizeof(saddr)) < 0){
perror("bind");
exit(1);
}
/*
* listenをソケットに対して発行する
*/
if (listen(fd1, 1) < 0) {
perror("listen");
exit(1);
}
len = sizeof(caddr);
/*
* accept()により、クライアントからの接続要求を受け付ける。
* 成功すると、クライアントと接続されたソケットのディスクリプタが
* fd2に返される。このfd2を通して通信が可能となる。
*/
for(;;){
if ((fd2 = accept(fd1, (struct sockaddr *)&caddr, &len)) < 0) {
perror("accept");
exit(1);
}
perror("accept ok");
/*
* fork()を使って作業専用のプロセスを作る
* 親プロセスは、次の接続要求を待つためにループし、
* 新しく生成された子プロセスは大文字に変換する作業だけを行う
*/
if ((pid = fork()) < 0) {
perror("fork");
exit(1);
} else if (pid == 0) {
/* fork()で新しく生成されたプロセスはこちら */
close(fd1);
ret = read(fd2, buf, sizeof(pksignin));//jushin rsuru baito su
perror("recieved");
////////////
/* 要求された(このサンプルは適当)データをクライアントに送り返す */
strcpy(buf, te); // test mojiretu wo kopi-suru
fprintf(stderr,buf); // console ni hyouji suru
write(fd2, buf, sizeof(pkresult));//kekka wo kaesu
///////////
ret = read(fd2, buf, 100);
exit(0);
}
/* 親プロセスはfd2を閉じて接続要求待ちのループに戻る */
close(fd2);
}
}
Windows側のクライアント 以下は「極めるVisualC++」のサンプルを動作確認して手を加えたもの
プロジェクト>>設定>>リンク に wsock32.lib を追加してビルドする
それから、緑部分は作った人よって違っているので自分のプロジェクトで出来た分を使用するように。
では最初に元クラス CxSock を作成する。ソケットを作成するクラス。
CxSockをベースとして、Cxserv、Cxclient、を作成する。
それぞれウィンドウズで動くサーバクラスと、ソケットクラス。
このサーバとクライアントが動作すると、そのクライアントはLINUXで動作しているサーバと
問題なく通信できる。
データ用のクラスとして、CSockDataも作成する。
実用的にするために、初期化でソケットを作成し、ゲーム中で常時データを交換する方式をテストする予定
CSockData クラスヘッダファイル
// SockData.h: CSockData クラスのインターフェイス
//
//////////////////////////////////////////////////////////////////
#if !defined(AFX_SOCKDATA_H__3BD54918_B26D_11D4_89F2_004026174071__INCLUDED_)
#define AFX_SOCKDATA_H__3BD54918_B26D_11D4_89F2_004026174071__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <winsock.h>
#include <process.h>
class CSockData
{
public:
char ServerAddress[80];
u_short PORT;
CSockData();
CSockData(const char *adrs, u_short p);
virtual ~CSockData();
};
#endif // !defined(AFX_SOCKDATA_H__3BD54918_B26D_11D4_89F2_004026174071__INCLUDED_)
------------------------------------------------------------------
CSockDataクラスソースファイル
------------------------------------------------------------------
// SockData.cpp: CSockData クラスのインプリメンテーション
//
/////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "client.h"
#include "SockData.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
/////////////////////////////////////////////////////////////////
// 構築/消滅
/////////////////////////////////////////////////////////////////
CSockData::CSockData()
{
}
CSockData::~CSockData()
{
}
CSockData::CSockData(const char *adrs, u_short p)
{
strcpy(ServerAddress, adrs);
PORT = p;
}
-------------------------------------------------------------------
基底クラス CxSockヘッダファイル
-------------------------------------------------------------------
// xSock.h: CxSock クラスのインターフェイス
//
//////////////////////////////////////////////////////////////////
#if !defined(AFX_XSOCK_H__3BD54916_B26D_11D4_89F2_004026174071__INCLUDED_)
#define AFX_XSOCK_H__3BD54916_B26D_11D4_89F2_004026174071__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <winsock.h>
#include <process.h>
class CxSock
{
public:
int status;
int errCode;
SOCKET theSocket;
SOCKADDR_IN theAddress;
u_short PORT;
CxSock();
CxSock(CxSock *soc);
void Copy(CxSock *soc);
void SetAddress(const char* adrs, u_short p);
void Create();
void Connect();
void Send(const char *buf, int nchar);
void Recv(char *buf, int nchar);
void ShutDown();
void Close();
virtual ~CxSock();
};
#endif // !defined(AFX_XSOCK_H__3BD54916_B26D_11D4_89F2_004026174071__INCLUDED_)
-----------------------------------------------------------------
基底クラス CxSock ソースファイル
-----------------------------------------------------------------
// xSock.cpp: CxSock クラスのインプリメンテーション
//
/////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "client.h"
#include "xSock.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
/////////////////////////////////////////////////////////////////
// 構築/消滅
/////////////////////////////////////////////////////////////////
int initWinSock=0;
CxSock::CxSock()
{
if(initWinSock==0){
WSADATA Data;
status=WSAStartup(MAKEWORD(1,1),&Data);
if(status!=0)
{
ExitProcess(1);
}
initWinSock=1;
}
}
CxSock::~CxSock()
{
}
CxSock::CxSock(CxSock *soc)
{
Copy(soc);
}
void CxSock::Copy(CxSock *soc)
{
theSocket=soc->theSocket;
memcpy(&theAddress, &soc->theAddress, sizeof(SOCKADDR_IN));
status=soc->errCode;
PORT=soc->PORT;
}
void CxSock::SetAddress(const char* adrs, u_short p)
{
unsigned long destAddr;
errCode=0;
PORT=p;
if(strlen(adrs)!=0)
{
destAddr=inet_addr(adrs);
memcpy(&theAddress.sin_addr, &destAddr, sizeof(destAddr));
} else {
memset(&theAddress,0,sizeof(theAddress));
theAddress.sin_addr.s_addr=htonl(INADDR_ANY);
}
theAddress.sin_port=htons(PORT);
theAddress.sin_family=AF_INET;
}
void CxSock::Create()
{
theSocket=socket(AF_INET, SOCK_STREAM, 0);
if(theSocket == INVALID_SOCKET)
{
status=WSACleanup();
if(status == SOCKET_ERROR)
{
errCode=1;
} else {
errCode=0;
}
}
}
void CxSock::Connect()
{
status=connect(theSocket, (LPSOCKADDR) &theAddress, sizeof(SOCKADDR_IN));
if(status == SOCKET_ERROR){
errCode=1;
status=closesocket(theSocket);
if(status==SOCKET_ERROR){
errCode=2;
status=WSACleanup();
if(status==SOCKET_ERROR){
errCode=3;
}
} else
errCode=0;
}
}
void CxSock::Send(const char *buf, int nchar)
{
int numsnt=send(theSocket, buf, nchar, 0); //NO_FLAGS_SET);
if(numsnt != nchar){
errCode=1;
} else
errCode=0;
}
void CxSock::Recv(char *buf, int nchar)
{
int numsnt=recv(theSocket, buf, nchar, 0); //NO_FLAGS_SET);
if(numsnt != nchar){
errCode=1;
} else
errCode=0;
}
void CxSock::ShutDown()
{
status=shutdown(theSocket, 2);
if(status == SOCKET_ERROR){
errCode=1;
} else
errCode=0;
}
void CxSock::Close()
{
status= closesocket(theSocket);
if(status == SOCKET_ERROR){
errCode=1;
} else
errCode=0;
}
------------------------------------------------------------------
CxSockから派生させたCxClientクラスのヘッダファイル
------------------------------------------------------------------
// xclient.h: Cxclient クラスのインターフェイス
//
//////////////////////////////////////////////////////////////////
#if !defined(AFX_XCLIENT_H__3BD54917_B26D_11D4_89F2_004026174071__INCLUDED_)
#define AFX_XCLIENT_H__3BD54917_B26D_11D4_89F2_004026174071__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <winsock.h>
#include <process.h>
#include "xSock.h"
#include "sockdata.h"
#define MAXBUFLEN 128
class Cxclient : public CxSock
{
public:
char buffer[MAXBUFLEN];
Cxclient();
Cxclient(Cxclient *clnt);
Cxclient(const char *adrs, u_short p);
Cxclient(CSockData *sd);
virtual void Start();
virtual void ServerLoop();
virtual void ClientLoop();
virtual void ClientShot();
virtual ~Cxclient();
};
#endif // !defined(AFX_XCLIENT_H__3BD54917_B26D_11D4_89F2_004026174071__INCLUDED_)
-----------------------------------------------------------------
CxClientクラスのソースファイル
-----------------------------------------------------------------
// xclient.cpp: Cxclient クラスのインプリメンテーション
//
/////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "client.h"
#include "xclient.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#define MAXBUFLEN 128
//////////////////////////////////////////////////////////////////
// 構築/消滅
//////////////////////////////////////////////////////////////////
Cxclient::Cxclient()
{
}
Cxclient::~Cxclient()
{
}
Cxclient::Cxclient(Cxclient *clnt)
:CxSock()
{
Copy(clnt);
}
Cxclient::Cxclient(const char *adrs, u_short p)
{
SetAddress(adrs, p);
if(errCode!=0) errCode=1;
}
Cxclient::Cxclient(CSockData *sd)
{
SetAddress(sd->ServerAddress, sd->PORT);
if(errCode!=0) errCode=1;
}
void Cxclient::Start()
{
Create();
if(errCode!=0) errCode=1;
else
{
Connect();
if(errCode!=0) errCode=2;
else
{
errCode=0;
}
}
}
void Cxclient::ServerLoop()
{
if(errCode==0){
while(1){
Recv(buffer, MAXBUFLEN);
if(errCode!=0){
break;
}
strupr(buffer);
Send(buffer, strlen(buffer) +1);
if(errCode!=0){
break;
}
}
}
}
void Cxclient::ClientLoop()
{
if(errCode==0){
char buffer[MAXBUFLEN];
while(1){
Send(buffer, strlen(buffer)+1); // buffer の中身を送る
if(errCode!=0) break;
Recv(buffer, MAXBUFLEN);
if(errCode!=0) break;
}
}
}
void Cxclient::ClientShot()
{
if(errCode==0){
// char buffer[MAXBUFLEN];
Send(buffer, strlen(buffer)+1); // buffer の中身を送る
// if(errCode!=0) break;
Recv(buffer, MAXBUFLEN);
// if(errCode!=0) break;
}
}
----------------------------------------------------------------
サーバクラス Cxserv ヘッダファイル
----------------------------------------------------------------
// xserv.h: Cxserv クラスのインターフェイス
//
/////////////////////////////////////////////////////////////////
#if !defined(AFX_XSERV_H__3BD54919_B26D_11D4_89F2_004026174071__INCLUDED_)
#define AFX_XSERV_H__3BD54919_B26D_11D4_89F2_004026174071__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <winsock.h>
#include <process.h>
#include "xSock.h"
#include "xserv.h"
#include "xclient.h"
class Cxserv : public CxSock
{
void Bind();
void Listen();
void Accept();
void SetClient(Cxclient *clnt);
public:
Cxclient *clntSocket;
Cxserv(u_short p, Cxclient *clnt);
Cxserv(Cxclient *clnt);
void Start();
void Loop();
Cxserv();
virtual ~Cxserv();
};
#endif // !defined(AFX_XSERV_H__3BD54919_B26D_11D4_89F2_004026174071__INCLUDED_)
----------------------------------------------------------------
サーバクラス Cxserv ソースファイル
----------------------------------------------------------------
// xserv.cpp: Cxserv クラスのインプリメンテーション
//
//////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "client.h"
#include "xserv.h"
#include <winsock.h>
#include <process.h>
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////
// 構築/消滅
//////////////////////////////////////////////////////////////////
Cxserv::Cxserv()
{
}
Cxserv::~Cxserv()
{
}
Cxserv::Cxserv(u_short p, Cxclient *clnt)
{
SetClient(clnt);
SetAddress("", p);
Create();
}
Cxserv::Cxserv(Cxclient *clnt)
{
SetClient(clnt);
SetAddress("", clnt->PORT);
Create();
}
void Cxserv::Start()
{
if(errCode==0){
Bind();
if(errCode!=0) errCode=2;
else
{
Listen();
if(errCode!=0) errCode=3;
else
errCode=0;
}
}
}
void Cxserv::SetClient(Cxclient *clnt)
{
clntSocket=clnt;
}
void Cxserv::Bind()
{
status=bind(theSocket, (LPSOCKADDR) &theAddress, sizeof(theAddress));
if(status==SOCKET_ERROR){
errCode=1;
}
else
errCode=0;
}
void Cxserv::Listen()
{
status=listen(theSocket,1);
if(status == SOCKET_ERROR){
errCode=1;
}
else
errCode=0;
}
void Cxserv::Accept()
{
int addrLen=sizeof(SOCKADDR_IN);
clntSocket->theSocket=accept(theSocket,(LPSOCKADDR) &clntSocket->theAddress,
&addrLen);
if(clntSocket->theSocket == INVALID_SOCKET){
errCode=1;
}
else
errCode=0;
}
VOID SockThread(VOID *cs)
{
Cxclient clientSocket((Cxclient*) cs);
clientSocket.ServerLoop();
clientSocket.ShutDown();
if(clientSocket.errCode!=0) clientSocket.Close();
// if(clientSocket.errCode!=0)
}
void Cxserv::Loop()
{
if(errCode==0){
DWORD threadID;
while(1){
Accept();
if(errCode!=0)
{
errCode=1;
} else {
threadID=_beginthread(SockThread,0,(void*)clntSocket);
if(threadID==-1){
clntSocket->Close();
// if(clntSocket->errCode!=0)
}
}
}
}
}
作成したソケットクラスの動作確認をするためのプロジェクトを作成する。
作成するのは、ウィンドウズで動くサーバと、クライアント。
サーバ、クライアントともに毎度おなじみのSDIで、
FormViewにボタンをひとつとEditボックスをひとつ配置する。
それぞれEditボックスは、メンバ変数を追加すること。
クライアント
動作確認用にボタンを押すと、サーバにデータを送コードを作成する。
以下はボタン1のハンドルのコード
Viewクラスのソースファイルには #include "xclient.h" を追加すること。
また、テスト用プロジェクトには、プロジェクト>>プロジェクトに追加、で
新しく作成したクラスのヘッダファイル、ソースファイルを追加する。
ピンク色部分に注目。接続するサーバのアドレスと、ポートを指定する。
----------------------------------------------------------------
クライアント
----------------------------------------------------------------
/////////////////////////////////////////////////////////////
// CClientView クラスのメッセージ ハンドラ
void CClientView::OnButton1()
{
// TODO: この位置にコントロール通知ハンドラ用のコードを追加してください
// Cxclient socket("192,168,1,2", (u_short)9005);
Cxclient socket("192.168.1.1", 9005);
socket.Start();
socket.ClientShot();
if(socket.errCode!=0){
switch(socket.errCode){
case 1: m_Edit1.SetWindowText("接続に失敗した"); break;
case 2: m_Edit1.SetWindowText("受信数が違う"); break;
}
} else
m_Edit1.SetWindowText(socket.buffer);
}