出典:WeChat公式アカウント「プログラミング学習ベース」
WinSockネットワークプログラミング
ビッグエンドリトルエンド
ビッグエンディアンモード:指数据的高字节保存在内存的低地址
例:12345(0x3039)の保管順序は 0x30、0x39
リトルエンディアンモード:指数据的高字节保存在内存的高地址
例:12345(0x3039)の保管順序は 0x39、0x30
ビッグエンドを判断する
方法1:
#include<stdio.h>
int main(int argc, char *argv[])
{
int i = 0x12345678;
char c = i;
if (c == 0x78)
{
printf("小端\n");
}
else
{
printf("大端\n");
}
return 0;
}
方法2:
#include<stdio.h>
int main(void)
{
int a = 0x12345678;
char *p = (char *)&a;
if (0x78 == *p)
{
printf("小端\n");
}
else
{
printf("大端\n");
}
return 0;
}
方法3:
#include<stdio.h>
typedef union NODE
{
int i;
char c;
}Node;
int main(int argc, char *argv[])
{
Node node;
node.i = 0x12345678;
if (0x78 == node.c)
{
printf("小端\n");
}
else
{
printf("大端\n");
}
return 0;
}
CSモデル
ソケットネットワークプログラミング
WSAStartup / WSACleanup
int WSAStartup ( WORD wVersionRequested,
LPWSADATA pWSAData );
それぞれが1WSAStartup
つのWSACleanup
呼び出しに対応することは許可されていません
ソケット
int socket(int af,
int type,
int protocol);
- AF:
AF_INET
、AF_INET6
、AF_LOCAL
WinSockはサポートのみAF_INET
- タイプ:
SOCK_STREAM
、SOCK_DGRAM
、SOCK_RAW
等
- プロトコル:
タイプがのSOCK_STREAM
場合、tcpプロトコルが使用されます
タイプがのSOCK_DGRAM
場合、udpプロトコルが使用されます
現時点ではprotocol
0として指定できます
タイプがのSOCK_RAW
場合、元のソケットが使用され、ICMPやその他のプロトコルなどのプロトコルをカスタマイズできます。
sockaddr_in
struct sockaddr_in {
short int sin_family, //地址家族
unsigned short int sin_port, //端口号
struct in_addr sin_addr, //IP地址
unsigned char sin_zero[8], //空字节,设为0
}
struct in_addr:
struct in_addr{
unsigned long s_addr;
}
ドット付き10進変換
inet_addr()
将一个点分十进制字符串转化为二进制的数
in_addr_t inet_addr(const char* cp);
- パラメータ:文字列、ドット付き10進IPアドレス
- 戻り値:
文字列が有効な場合、文字列は32ビットのバイナリネットワークバイトオーダーIPV4アドレスに変換されます。それ以外の場合は、INADDR_NONEになります。
inet_ntoa()
将二进制数转换为一个点分十进制字符串
char *inet_ntoa(struct in_addr);
- パラメータ:in_addrは、32ビットIPV4アドレスを表すために使用される構造体です。
- 戻り値:スタティックメモリ内のドット付き10進文字列のポインタを返します
ポート変換機能
TCP / IPプロトコルは、ネットワークのバイト順序、つまりビッグエンディアンを一律に使用します。
u_short htons(u_short hostshurt) //主机字节顺序转网络字节顺序
u_long htonl(u_long hostshurt) //主机字节顺序转网络字节顺序
u_short ntohs(u_short hostshurt) //网络字节顺序转主机字节顺序
u_long ntohl(u_long hostshurt) //网络字节顺序转主机字节顺序
通常htons
、ポート変換に使用されます
練る
int bind(
SOCKET s, //套接字句柄
onst struct sockaddr* name, //本地地址
int namelen //地址长度
);
聴く
int listen(
SOCKET s, //套接字句柄
int backlog //监听队列允许保持的最大连接数量
);
受け入れる
SOCKET accept(
SOCKET s, //套接字句柄
struct sockaddr* addr, //协议族渎职
int* addrlen //地址长度
);
接続する
int connect(
SOCKET s, //套接字句柄
const struct sockaddr* name, //协议族地址
int namelen //地址长度
);
tcpサーバー
#include <winsock2.h> // 为了使用Winsock API函数
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
// 告诉连接器与WS2_32库连接
#pragma comment(lib,"WS2_32.lib")
int main(int argc, char* argv[])
{
// 初始化WS2_32.dll
WSADATA wsaData;
WORD sockVersion = MAKEWORD(2, 2);
WSAStartup(sockVersion, &wsaData); //请求了一个2.2版本的socket
// 创建套节字
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s == INVALID_SOCKET)
{
printf("Failed socket() \n");
WSACleanup();
return 0;
}
// 填充sockaddr_in结构
sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(8888); //8888端口
//sin.sin_addr.S_un.S_addr = INADDR_ANY; //本地地址
sin.sin_addr.S_un.S_addr = inet_addr("169.254.211.52"); //172.19.12.44
// 绑定这个套节字到一个本地地址
if (bind(s, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
{
printf("Failed bind() \n");
WSACleanup();
return 0;
}
// 进入监听模式
if (listen(s, 2) == SOCKET_ERROR) //最大连接数为2
{
printf("Failed listen()");
WSACleanup();
return 0;
}
printf("Start listen:\n");
// 循环接受客户的连接请求
sockaddr_in remoteAddr;
int nAddrLen = sizeof(remoteAddr);
SOCKET client;
char szText[] = "hello!\n";
while (TRUE)
{
// 接受一个新连接
client = accept(s, (SOCKADDR*)&remoteAddr, &nAddrLen);
if (client == INVALID_SOCKET)
{
printf("Failed accept()");
continue;
}
printf(" 接受到一个连接:%s \r\n", inet_ntoa(remoteAddr.sin_addr));
// 向客户端发送数据
send(client, szText, strlen(szText), 0);
// 关闭同客户端的连接
closesocket(client);
}
// 关闭监听套节字
closesocket(s);
// 释放WS2_32库
WSACleanup();
return 0;
}
tcpクライアントアドレス
#include <winsock2.h>
#include <stdio.h>
#include <windows.h>
// 告诉连接器与WS2_32库连接
#pragma comment(lib,"WS2_32.lib")
int main(int argc, char* argv[])
{
// 初始化WS2_32.dll
WSADATA wsaData;
WORD sockVersion = MAKEWORD(2, 2);
WSAStartup(sockVersion, &wsaData);
// 创建套节字
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s == INVALID_SOCKET)
{
printf("Failed socket() \n");
WSACleanup();
return 0;
}
// 填写远程地址信息
sockaddr_in servAddr;
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(8888);
// 如果你的计算机没有联网,直接使用本地地址127.0.0.1
servAddr.sin_addr.S_un.S_addr = inet_addr("169.254.211.52");
if (connect(s, (sockaddr*)&servAddr, sizeof(servAddr)) == -1)
{
printf("Failed connect() \n");
WSACleanup();
return 0;
}
// 接收数据
char buff[256];
int nRecv = recv(s, buff, 256, 0);
if (nRecv > 0)
{
buff[nRecv] = '\0';
printf(" 接收到数据:%s", buff);
}
// 关闭套节字
closesocket(s);
// 释放WS2_32库
WSACleanup();
return 0;
}