winsock的初始化
进行winsock编程时,首先必须调用WSAStartup函数,设置程序中用到的Winsock版本,并初始化相应版本的库。
#include<winsock2.h>
int WSASartup(WORD wVersionRequested , LPWSADATA lpWSAData );
//成功时返回0,失败时返回非零的错误代码值。
wVersionRequested 程序员要用的Winsock版本信息。
lpWSAData WSADATA结构体变量的地址值
有必要给出上述两个参数的详细说明。第一个,Winsock中存在多个版本,应准备WORD类型的(WORD是通过typedef声明定义的unsiged short类型)套接字版本信息,并传递给该函数的一个参数wVersionRequested。若版本为1.2,则其中1是主版本号,2是副版本号,应传递0x0201。
借助MAKEWORD宏函数则能轻松构建WORD型版本信息。
MAKEWORD(1 , 2); //主版本为1,副版本为2,返回0x0201
MAKEWORD(2 , 2); //主版本为2,副版本为2,返回0x0202
winsock库注销
#include<winsock2.h>
int WSACleanup();
//成功时返回0,失败时返回SOCKET_ERROR.
调用该函数时,winsock相关库将归还windows操作系统,无法再调用winsock相关函数。从原则上讲,无需再使用winsock函数时才调用该函数,但通常都在程序结束之前调用。
socket函数
//成功时返回socket句柄,失败时返回INVALID_SOCKET。
SOCKET socket(int af , int type , int protocol);
af 套接字中使用的协议族信息
type 套接字数据传输类型信息
protocol 计算机间通信中使用的协议信息
协议族类型:
PF_INET IPv4互联网协议族
PF_INET6 IPv6互联网协议族
PF_LOCAL 本地通信的unix协议族
PF_PACKET 底层套接字的协议族
PF_IPX IPX Novell协议族
套接字类型(type):
1.面向连接的套接字(SOCK_STREAM)
特点:
1)传输过程中数据不会消失
2)按顺序传输数据
3)传输的数据不存在数据边界
2.面向消息的套接字(SOCK_DGRAM)
特点:
1)强调快速传输而非传输顺序
2)传输的数据可能丢失也可能损毁
3)传输的数据有数据边界
4)限制每次传输的数据大小
3协议信息(填写0 根据前面的两个参数,默认填写合适的协议)
1)TCP套接字
socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
2)UDP套接字
socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
bind函数
//成功时返回0,失败时返回SOCKET_ERROR
int bind(Socket s,const struct sockaddr * name,int namelen);
s 套接字句柄
name 存有地址信息的结构体变量地址值
namelen 第二个结构体变量的长度
listen函数
//成功时返回0,失败时返回SOCKET_ERROR
int listen(SOCKET s,int backlog);
accept函数
//成功时返回套接字句柄,失败时返回INVALID_SOCKET。
SOCKET accept(SOCKET s,struct sockaddr* addr,int * addrlen);
connect函数
//成功时返回0,失败时返回SOCKET_ERROR
int connect(SOCKET s,const struct sockaddr* name,int namelen);
cloessocket函数
//成功时返回0,失败时返回SOCKET_ERROR
int closesocket(SOCKET S);
传输函数
//成功时返回传输字节数,失败时返回SOCKET_ERROR
int send(SOCKET s, const char*buf , int len , int flags );
s 表示数据传输对象连接的套接字句柄值
buf 保存带传输数据的缓冲地址值
len 要传输的字节数
flags 传输数据时用到的多种选项信息
//成功时返回传输字节数(收到EOF时为0),失败时返回
SOCKET_ERROR
int recv(SOCKET s, const char*buf , int len , int flags );
s 表示数据传输对象连接的套接字句柄值
buf 保存带传输数据的缓冲地址值
len 要传输的字节数
flags 传输数据时用到的多种选项信息
服务器:
//服务器代码
#include<stdlib.h>
#include<stdio.h>
#include<WinSock2.h>
#pragma comment(lib,"ws2_32.lib") //显示调用ws2_32.lib
void ErrorHanding(char* message);
int main() {
WSADATA wsadata;
SOCKET hserverSocket, hclientSocket;
SOCKADDR_IN serveraddr, clientaddr;
int szClientAdd;
char message[] = "这是服务器!";
if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0) //初始化winsock库
ErrorHanding("WSAStartup() error");
hserverSocket = socket(PF_INET, SOCK_STREAM, 0); // IPV4 面向连接传输
if (hserverSocket == INVALID_SOCKET)
ErrorHanding("socket() error");
memset(&serveraddr, 0, sizeof(serveraddr));//清空,值全为0
serveraddr.sin_family = AF_INET; //IPv4
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); //自动寻找本机地址
serveraddr.sin_port = htons(6666); //端口为 6666
//绑定服务器地址
if (bind(hserverSocket, (SOCKADDR*)&serveraddr, sizeof(serveraddr)) == SOCKET_ERROR)
ErrorHanding("bind() error");
//使套接字成为服务器套接字
if (listen(hserverSocket,5) == SOCKET_ERROR) {
ErrorHanding("listen() error");
}
szClientAdd = sizeof(clientaddr);
hclientSocket = accept(hserverSocket, (SOCKADDR*)&clientaddr, &szClientAdd);
if (hclientSocket == INVALID_SOCKET)
ErrorHanding("accept() Error");
send(hclientSocket, message, sizeof(message),0);
closesocket(hclientSocket); //关闭客户套接字
closesocket(hserverSocket); //关闭服务器套接字
WSACleanup(); //清理winsock库
return 0;
}
void ErrorHanding(char* message) {
fputs(message, stderr);
fputc('\n', stderr);
}
客户端代码:
#include<stdlib.h>
#include<stdio.h>
#include<WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
void ErrorHanding(char* message);
int main() {
WSADATA wsadata;
SOCKET hclientsocket;
SOCKADDR_IN servAddr;
char message[30];
int strlen;
if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0)
ErrorHanding("WSAStartup() error");
hclientsocket = socket(PF_INET, SOCK_STREAM, 0);
if (hclientsocket == INVALID_SOCKET)
ErrorHanding("socket() error");
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); //回送地址,访问本地
servAddr.sin_port = htons(6666); //端口号
//客户端套接字通过目的地址建立连接
if (connect(hclientsocket, (SOCKADDR*)&servAddr, sizeof(servAddr)))
ErrorHanding("conect() error");
//读取数据
strlen = recv(hclientsocket, message, sizeof(message),0);
if (strlen == -1) ErrorHanding(" read() error");
printf("message from server:%s \n", message);
getchar();
closesocket(hclientsocket);
WSACleanup();
return 0;
}
void ErrorHanding(char* message) {
fputs(message, stderr);
fputc('\n', stderr);
}