1.4 基于Windows的套接字相关函数及示例
#inclde <winsock2.h>
SOCKET socket(int af, int type, int protocol);
// 成功返回套接字句柄,否则INVALID_SOCKET
int bind(SOCKET s, const struct sockaddr *name, int namelen);
// 分配IP和端口号
// 成功返回0,否则SOCKET_ERROR
int listen(SOCKET s,int backlog);
// 使得套接字可接受客户端连接
// 成功返回0,否则SOCKET_ERROR
SOCKET accept(SOCKET s, struct sockaddr *addr, int *addrlen);
// 受理客户端连接
// 成功返回套接字句柄,否则INVALID_SOCKET
int connect(SOCKET s, const struct sockaddr *addr, int namelen);
// 从客户端发送连接请求
// 成功返回0,否则SOCKET_ERROR
int closesocket(SOCKET s);
// 关闭套接字的函数
// 成功返回0,否则SOCKET_ERROR
虽然返回值不太一样,但是函数名差不多吧。
Windows中的文件句柄和套接字句柄
Windows
中通过系统调用函数创建文件会返回句柄(handle
),句柄其实相当于Linux
中的文件描述符。
创建基于Windows的服务器端和客户端
服务端示例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
void error_handling(const char* message);
int main(int argc, char* argv[])
{
WSADATA wsaData;
SOCKET hServSock, hClntSock;
SOCKADDR_IN servAddr, clntAddr;
int szClntAddr;
char message[] = "Hello World!";
if (argc != 2) {
printf("Usage: %s <port> \n", argv[0]);
exit(1);
}
if (WSAStartup(MAKEWORD(2,2),&wsaData) != 0)//初始化
error_handling("WSAStartup() error");
hServSock = socket(PF_INET,SOCK_STREAM, 0);//创建套接字
if(hServSock == INVALID_SOCKET)
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
servAddr.sin_port = htons(atoi(argv[1]));
//分配IP和端口
if (bind(hServSock, (SOCKADDR *)&servAddr, sizeof(servAddr)) == SOCKET_ERROR) {
error_handling("bind() error");
}
//使得该套接字成为服务器端的套接字
if (listen(hServSock, 5) == SOCKET_ERROR) {
error_handling("listen() error");
}
szClntAddr = sizeof(clntAddr);
//接受客户端连接请求
hClntSock = accept(hServSock, (SOCKADDR *)&clntAddr, &szClntAddr);
if (hClntSock == INVALID_SOCKET)
error_handling("accept() error");
//传输数据
send(hClntSock, message, sizeof(message), 0);
closesocket(hClntSock);
closesocket(hServSock);
WSACleanup();//注销套接字库
return 0;
}
void error_handling(const char* message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
客户端示例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
void error_handling(const char* message);
int main(int argc, char* argv[])
{
WSADATA wsaData;
SOCKET hSocket;
SOCKADDR_IN servAddr;
char message[30];
int strLen;
if (argc != 3) {
printf("Usage: %s <IP> <port> \n", argv[0]);
exit(1);
}
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
error_handling("WSAStartup() error");
hSocket = socket(PF_INET, SOCK_STREAM, 0);
if (hSocket == INVALID_SOCKET)
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = inet_addr(argv[1]);//此处需要到项目中在属性里的C/C++下属的常规里设置SDL检查为否,否则会报错。
servAddr.sin_port = htons(atoi(argv[2]));
if (connect(hSocket, (SOCKADDR*)&servAddr, sizeof(servAddr)) == SOCKET_ERROR) {
error_handling("connect() error");
}
strLen = recv(hSocket, message, sizeof(message) - 1, 0);
if (strLen == -1)
error_handling("read() error");
printf("Messagee from server: %s \n", message);
closesocket(hSocket);
WSACleanup();
return 0;
}
void error_handling(const char* message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
基于Windows的I/O函数
Linux
中的套接字是文件,因此可以共用文件I/O函数
的read
和write
。但是Windows
中不同,它严格区分文件I/O
和套接字I/O
。
#include <winsock2.h>
int send(SOCKET s, const char * buf, int len, int flags);
//成功返回传输字节数,否则SOCKET_ERROR
int recv(SOCKET s, const char * buf, int len, int flags);
//成功返回接受的字节数(收到EOF为0),否则SOCKET_ERROR
// s ---- 数据接收对象连接的套接字句柄值
// buf -- 要传输或保存数据的缓冲地址值
// len -- 要传输的字节数和能接受的最大的字节数
// flags -- 选项信息
此函数与write相比只是多出来flags,其实Linux中也有send和recv他们同属于BSD套接字。
使用read和write只是为了说明Linux中的套接字是文件。