写在开头:
开坑(实现一个网络Game ,emmmm选一个简单的种类,棋类:),象棋)
参照书目:winsock网络编程经络+Unix网络编程以及msdn文档https://msdn.microsoft.com/en-us/library/windows/desktop/ms741394(v=vs.85).aspx
先在windows下实现一个简易C/S,然后在把服务端换在unix端。
因为没有涉及到AI,所以象棋的逻辑比较容易实现,就当是个小程序练习了。主要是学习一下计网。
Unix与windows socket
BSD socket
unix socket是在操作系统中实现的,是操作系统的一部分,程序调用socket是系统调用。
windows是把socket放在动态链接库中。
这种形式只是内部实现不同,对于开发者编写代码都是一致的
winsock
微软根据BSD模型开发的,对windows接口和消息驱动机制很友好,与BSDsocket很多接口一致(简化了移植工作)
winsock
process(MSDN)
Server
Initialize Winsock.
Create a socket.
Bind the socket.
Listen on the socket for a client.
Accept a connection from a client.
Receive and send data.
Disconnect.
Client
Initialize Winsock.
Create a socket.
Connect to the server.
Send and receive data.
Disconnect.
tips
- lib
winsock包含两个版本,winsock2.h为兼容winsock.h的头文件 winsock.h只支持TCP/IP协议栈,winsock2.h +支持多个传输层协议 - 常量
winsock程序定义需要许多常量,分别在lib中或者需要自己实现,以方便维护 - winsock初始化
使用winsock之前需要WSAStartup初始化WinScok动态链接库。调用失败时返回错误码,每次WSAStartup结束都应该有WSACleanUp - port 和ip
sockaddr_in结构体来初始化
在linux和windows中,该结构体表示的意义相同,但具体实现细节不同,一下是windows下具体结构及意义
struct sockaddr_in{
short sin_family;
unsigned short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
sin_family 地址簇,内核来判断如何解释该地址
sin_port 端口号
sin_addr 32位地址结构体 windows在该结构体使用union结构
sin_zero 填充字节,使之大小等于SOCKADDR
第一个demo
Client
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib, "ws2_32") /* WinSock 使用的库函数 */
#define ECHO_DEF_PORT 7 /* 连接的缺省端口 */
#define ECHO_BUF_SIZE 256 /* 缓冲区的大小 */
int main()
{
WSADATA wsa_data;
SOCKET echo_soc = 0; /* socket 句柄 */
struct sockaddr_in serv_addr; /* 服务器地址 */
unsigned short port = ECHO_DEF_PORT;
int result = 0, send_len = 0;
char *test_data = "Hello World!", recv_buf[ECHO_BUF_SIZE];
printf("run");
const char *Server_Ip = "127.0.0.1";
const port = 27;
WSAStartup(MAKEWORD(2,0), &wsa_data);/* 初始化 WinSock资源 */
send_len = strlen(test_data);
/* 服务器地址 */
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
serv_addr.sin_addr.s_addr = inet_addr(Server_Ip);
if (serv_addr.sin_addr.s_addr == INADDR_NONE)
{
printf("[ECHO] invalid address\n");
return -1;
};
echo_soc = socket(AF_INET, SOCK_STREAM, 0); /* 创建 socket */
result = connect(echo_soc, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (result == 0) /* 连接成功 */
{
result = send(echo_soc, test_data, send_len, 0);
result = recv(echo_soc, recv_buf, ECHO_BUF_SIZE, 0);
}
if (result > 0)
{
recv_buf[result] = 0;
printf("[Echo Client] receives: \"%s\"\r\n", recv_buf);
}
else
printf("[Echo Client] error : %d.\r\n", WSAGetLastError());
closesocket(echo_soc);
WSACleanup();
int a;
scanf("%d", &a);
return 0;
}
Server
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib, "ws2_32") /* WinSock 使用的库函数 */
#define ECHO_DEF_PORT 7 /* 侦听的缺省端口 */
#define ECHO_BUF_SIZE 256 /* 缓冲区的大小 */
int main(int argc, char **argv)
{
WSADATA wsa_data;
SOCKET echo_soc = 0, /* 侦听 socket 句柄 */
acpt_soc = 0;
struct sockaddr_in serv_addr, /* socket的本地地址 */
clnt_addr; /* socket的远端地址 */
unsigned short port = ECHO_DEF_PORT;
int result = 0;
int addr_len = sizeof(struct sockaddr_in);
char recv_buf[ECHO_BUF_SIZE];
if (argc == 2)
port = atoi(argv[1]);
WSAStartup(MAKEWORD(2,0), &wsa_data);/* 初始化 WinSock资源 */
echo_soc = socket(AF_INET, SOCK_STREAM, 0); /* 创建 socket */
/* socket 的本地地址 */
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
serv_addr.sin_addr.s_addr = INADDR_ANY;
result = bind(echo_soc, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (result == SOCKET_ERROR)
{
printf("[Echo Server] bind error: %d\n", WSAGetLastError());
closesocket(echo_soc);
return -1;
}
listen(echo_soc, SOMAXCONN);
printf("[Echo Server] is running ... ...\n");
while (1)
{
acpt_soc = accept(echo_soc, (struct sockaddr *)&clnt_addr, &addr_len);
if (acpt_soc == INVALID_SOCKET)
{
printf("[Echo Server] accept error: %d\n", WSAGetLastError());
break;
}
result = recv(acpt_soc, recv_buf, ECHO_BUF_SIZE, 0);
if (result > 0)
{
recv_buf[result] = 0;
printf("[Echo Server] receives: \"%s\", from %s\r\n",
recv_buf, inet_ntoa(clnt_addr.sin_addr));
result = send(acpt_soc, recv_buf, result, 0);
}
closesocket(acpt_soc);
}
closesocket(echo_soc);
WSACleanup();
return 0;
}