一,ws2.32.lib链接
winsock.h使用之前需要链接ws2.32.lib,否则会报错。
链接方式:
DEVC++:
点击“工具”,选择“编译选项”
在“在链接时加入以下参数”中填写“-lws2_32”
VC:
在源文件的开头添加以下代码:
#pragma comment(lib, "ws2_32.lib")
二,基本函数,
初始化Winsock:
WSADATA wsa;
WSAStartup(MAKEWORD(2, 2), &wsa)
//版本号2.2
//0为初始化成功
套接字创建:
SOCKET sk;//定义套接字
struct sockaddr_in sa;//定义ipv4和端口号
sk = socket(AF_INET, SOCK_STREAM, 0)
// 创建套接字,INVALID_SOCKET为创建失败
设置服务器地址:
sa.sin_family = AF_INET;//地址
sa.sin_addr.s_addr = INADDR_ANY;//接受来自任何网络接口的连接
//客户端套接字应该把INADDR_ANY改成inet_addr("服务器ip地址");"127.0.0.1"为连接本机
sa.sin_port = htons(12345);//创建端口号,服务器与客户端端口号需一致
绑定套接字:
bind(sk, (struct sockaddr *)&sa, sizeof(sa))
//将一个本地地址赋予一个套接字,SOCKET_ERROR为绑定失败
监听连接 :
listen(sk,1);//SOCKET_ERROR为监听失败
接受连接:
SOCKET cs;//cs为客户端套接字
struct sockaddr_in ca;
int len = sizeof(ca);//把ca长度赋给len
cs = accept(sk, (struct sockaddr *)&ca, &len);
//返回INVALID_SOCKET为连接失败
发送数据:
char i[3];
send(cs//对应套接字
,i//要发送的字符或字符串(字符串末为最好不填,否则可能接收到的数据会出错)
,3//发送长度
,0//正常发送
);
接收数据:
char i[2];
recv(cs,//对应套接字
i,//接收的字符或字符串
2,//接收长度
0,//正常发送
)
示例代码:
服务器:
#include <stdio.h>
#include <winsock.h>
#pragma comment(lib, "ws2_32.lib")
//#include <windows.h>
int main() {
WSADATA wsa;
SOCKET sk, cs;
struct sockaddr_in sa,ca;
int len = sizeof(ca);
// 初始化Winsock
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0){
printf("初始化失败\n");
exit(0);
}
// 创建套接字
if((sk=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET){
printf("套接字创建失败\n");
}
// 设置服务器地址
sa.sin_family=AF_INET;//地址
sa.sin_addr.s_addr=INADDR_ANY;//接受来自任何网络接口的连接
sa.sin_port=htons(12345);//创建端口号
// 绑定套接字
if(bind(sk,(struct sockaddr *)&sa,sizeof(sa))==SOCKET_ERROR){
printf("绑定失败\n");
exit(0);
}
// 监听连接
if(listen(sk,1)==SOCKET_ERROR)
{
printf("监听失败\n");
exit(0);
}
printf("等待客户端连接...\n");
// 接受连接
/*
if ((cs = accept(sk, (struct sockaddr *)&ca, &len))==INVALID_SOCKET)
{
printf("连接失败\n");
exit(0);
}
printf("连接成功\n");
send(cs,"hello",100,0);//发送数据
char message[100];
scanf("%s",message);
while(message!="-1"){
if(send(cs,message,100,0)<0)
{
printf("发送失败\n");
}
scanf("%s",message);
}
send(cs,message,100,0);
closesocket(cs);
closesocket(sk);
WSACleanup();
getchar();
}
服务器用于接收字符串并发送给客户端,当接收到“-1”时结束通信;(一个服务器只对应一个客户端)
客户端:
#include <stdio.h>
#include <winsock.h>
#include<windows.h>
#include<bits/stdc++.h>
using namespace std;
int main() {
WSADATA wsa;
SOCKET cs;
struct sockaddr_in sa;
// 初始化Winsock
if(WSAStartup(MAKEWORD(2, 2),&wsa)!=0){
printf("初始化失败\n");
exit(0);
}
// 创建套接字
if((cs=socket(AF_INET, SOCK_STREAM,0))==INVALID_SOCKET){
printf("套接字创建失败\n");
exit(0);
}
// 设置服务器地址
sa.sin_family=AF_INET;//ipv4
sa.sin_addr.s_addr=inet_addr("127.0.0.1");//服务端ip地址(127.0.0.1为连接本机,请根据自己的服务器ip地址进行修改)
sa.sin_port=htons(12345);//端口号
// 连接到服务器
if(connect(cs,(struct sockaddr *)&sa,sizeof(sa))<0)
{
printf("连接失败\n");
exit(0);
}
printf("连接成功\n");
char i[100];
int j;
while(1)
{
if(recv(cs,i,100,0)>0){
if(i=="-1"){
printf("连接断开");
break;
}
printf("接收:%s\n",i);
}
}
closesocket(cs);
WSACleanup();
getchar();
}
客户端用于接收服务器发送的数据并打印;
线程函数:
上面的代码中一个服务器只对应一个客户端,这样只有当处理完一个客户端时才能处理下一个客户端,使用线程函数CreateThread();可以使服务器同时处理多个客户端;
使用方法:
CreateThread(NULL,
0,//指定线程的堆栈大小,0为默认值
s,//DWORD WINAPI类型的函数,需要自己定义,函数中包含一个LPVOID类型数据,可用SOCKET tc=(SOCKET)cs;把LPVOID数据转化成套接字
(LPVOID)cs,//被(LPVOID)转化成LPVOID类型的套接字
0,
NULL//线程ID,NULL为不返回线程ID线程ID可以保存在HANDLE类中,可以通过线程ID对对应线程进行对应操作
);
示例代码:
服务器:
#include <stdio.h>
#include <winsock.h>
#pragma comment(lib, "ws2_32.lib")
//#include <windows.h>
DWORD WINAPI s(LPVOID cs){
SOCKET tcs=(SOCKET)cs;
char i[3];
i[0]=48;
i[2]=0;
for(i[1]=48;i[1]<=58;i[1]++)
{
Sleep(1000);
send(tcs,i,3,0);
}
i[0]=-1;
send(tcs,i,3,0);
closesocket(tcs);
return 0;
}
int main() {
WSADATA wsa;
SOCKET sk, cs;
struct sockaddr_in sa, ca;
int len = sizeof(ca);
// 初始化Winsock
if(WSAStartup(MAKEWORD(2,2),&wsa)!=0){
printf("初始化失败\n");
exit(0);
}
// 创建套接字
if((sk=socket(AF_INET, SOCK_STREAM,0))==INVALID_SOCKET){
printf("套接字创建失败\n");
}
// 设置服务器地址
sa.sin_family=AF_INET;//地址
sa.sin_addr.s_addr=INADDR_ANY;//接受来自任何网络接口的连接
sa.sin_port=htons(12345);//创建端口号
// 绑定套接字
if(bind(sk,(struct sockaddr *)&sa,sizeof(sa))==SOCKET_ERROR){
printf("绑定失败\n");
exit(0);
}
// 监听连接
if(listen(sk,1)==SOCKET_ERROR)
{
printf("监听失败\n");
exit(0);
}
printf("等待客户端连接...\n");
while(1){
cs=accept(sk,(struct sockaddr *)&ca,&len);
CreateThread(NULL,0,s,(LPVOID)cs,0,NULL);//线程函数
}
closesocket(cs);
closesocket(sk);
WSACleanup();
getchar();
}
服务器运行时每隔一秒向客户端发送依次从01~09的字符串,可接受并同时处理多个客户端;
客户端:
#include <stdio.h>
#include <winsock.h>
#include<windows.h>
int main() {
WSADATA wsa;
SOCKET cs;
struct sockaddr_in sa;
// 初始化Winsock
if(WSAStartup(MAKEWORD(2, 2),&wsa)!=0){
printf("初始化失败\n");
exit(0);
}
// 创建套接字
if((cs=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET){
printf("套接字创建失败\n");
exit(0);
}
sa.sin_family=AF_INET;//ipv4
sa.sin_addr.s_addr=inet_addr("127.0.0.1");//服务端ip地址,"127.0.0.1"为连接本机
sa.sin_port=htons(12345);//端口号
// 连接到服务器
if(connect(cs,(struct sockaddr *)&sa,sizeof(sa))<0){
printf("连接失败\n");
exit(0);
}
printf("连接成功\n");
char i[3];
int j;
while(1)
{
if(recv(cs,i,3,0)>0){
if(i[0]==-1){
printf("连接断开");
break;
}
printf("接收:%s\n",i);
}
}
closesocket(cs);
WSACleanup();
getchar();
}
客户端用于随时接收服务器发送的数据并打印出来;
运行结果: