首页 > 编程知识 正文

c语言windows网络编程,c语言网络编程书籍

时间:2023-05-05 02:39:05 阅读:114466 作者:3610

基于文章目录TCP/IP协议的C/S模型服务端1 .打开网络库2 .查看版本3。 创建套接字4。 绑定地址和端口5. listen以接收网络端口6. accept并等待与客户端的连接。 创建客户端套接字。 7 .发送和接收客户端和消息客户端

基于TCP/IP协议的C/S模型

特点:面向连接、可靠、基于字节流的传输层协议。

C/S是客户端/服务器型号。

socket :套语

服务端头文件,网络库:

#include WinSock2.h //网络标头,windows套接字第2版#pragmacomment(lib,' ws2_32.lib ' ) /网络库加载,windows 无论是32位//32位环境还是64位环境,无论是第一版还是第二版,ws2_32.lib 1.中的网络库//函数原型wsa startup (wordwversionrequested,LP www

参数1 :

正在使用的库的版本。 类型为word (从统一短整型转换而来) )。

定义word:word version=生成word (2,2 ); 其中MAKEWORD (主版本、次版本) )。

参数2 :

如果类型为LPWSADATA lpWSAData,系统将检索网络配置信息并返回此参数。 如果参数前面有LP前缀,则传递对应的类型变量地址

定义WSADATA结构并传递到其地址WSADATA dat;

返回值:

返回值为int型,如果打开网络库成功则返回0,如果失败则返回各种错误代码

word version=make word (2,2 ); WSADATA dat; intn RES=wsa startup (版本,dat ); //在最后一个程序结束前一定要关闭网络库: WSACleanup (); 2 .检查if版本(2!=hibyte(dat.wversion )|| 2!=lobyte(dat.wversion ) /版本为WSACleanup ); //关闭库return 0.创建socketsocket。 是封装复杂协议体系、运行流程的一个接口,划分复杂协议和编程,直接操作socket,方便网络程序的开发;

本质上是数据类型,是表示当前的APP应用、协议等信息的整数

//函数原型套接字(intaf,int type,int protocol ); 参数1 :地址类型

IPv4地址: AF_INET、IPv6地址: AF_INET(两种常见) )

参数2 :字节类型

最常用的是:

SOCK_STREAM是一种支持数据报的字节类型,可靠,基于双向字节流,并使用TCP协议

SOCK_DGRAM,支持数据报字节类型,使用的协议是UDP协议

参数3 :协议类型

最常用的是:

IPPROTO_TCP:TCP协议; IPPROTO_UDP:UDP协议

返回值:

已成功返回可用套接字。 如果套接字未使用,请务必销毁: closesocket (

socketsock=socket(af_inet,SOCK_STREAM,IPPROTO_TCP ); 4 .绑定地址和端口//函数原型int bind (套接字,常数结构套接字名称,int名称); 角色:

将地址和端口号绑定到创建的套接字

参数1 :自己创建的套接字

参数2 :指向包含地址类型、IP地址和端口号信息的sockaddr结构的指针

使用方法:为了方便使用,使用sockaddr_in类型

sockaddr_in sin={};

sin.sin_family=AF_INET; 地址类型

sin.sin_port=htons(4567; 端口号

sin.sin _ addr.s _ un.s _ addr=inet _ addr (“192.168.1.4”); IP地址

使用的端口号必须是本机未使用的端口号。 如果不知道,可以通过以下方法查看:

打开cmd并键入netstat -ano以显示所有使用的端口

输入netstat -ano|findstr “12345”确定是否被占用

最后用力转动sockaddr_in类型

成sockaddr* 即 (sockaddr*)&sin

参数三:参数二的类型大小,常用sizeof()

返回值:成功返回0,失败返回SOCKET_ERROR,具体错误码通过 int WSAGetLastError(void) 获得

sockaddr_in sin = {};sin.sin_family = AF_INET;sin.sin_port = htons(4567);sin.sin_addr.S_un.S_addr = inet_addr("192.168.1.4");//2 bind 绑定用于接受客户端链接的网络端口if (SOCKET_ERROR == bind(sock, (sockaddr*)&sin, sizeof(sin))){cout << "绑定网络端口失败" << endl;}else {cout << "绑定网络端口成功" << endl;} 5. listen监听网络端口 intlisten( SOCKET s, int backlog );

作用:

将套节字置入正在传入侦听连接的状态

参数一:服务器端socket

参数二:挂起连接队列的最大长度

比如有100个用户连接请求,系统一次只能处理20个,剩下的80个就会进入此队列,一般填写SOMAXCONN,让系统自动选择

返回值:成功返回0,失败返回SOCKET_ERROR

if (SOCKET_ERROR == listen(sock, 5)){cout << "监听网络端口失败" << endl;}else {cout << "监听网络端口成功" << endl;} 6. accept等待客户端连接(创建客户端socket) SOCKETaccept( SOCKET s, struct sockaddr * addr, int * addrlen );

作用:

listen监听客户端的连接请求,accept将客户端的信息绑定到一个socket上,然后通过返回值返回

参数一:自己创建的socket

参数二:客户端的地址端口信息结构体,和bind函数的第二个参数一样

参数三:参数二的大小

PS:参数二,三都可以设置为NULL,不直接得到客户端的地址,端口等信息

返回值:成功返回客户端socket,失败返回INVALID_SOCKET

sockaddr_in clientAddr = {};int nAddrLen = sizeof(sockaddr_in);SOCKET cSock = INVALID_SOCKET;cSock = accept(sock, (sockaddr*)&clientAddr, &nAddrLen);if (INVALID_SOCKET == cSock){cout << "错误,接受到无效客户端SOCKET..." << endl;} 7. 与客户端收发消息

接收消息:得到指定客户端(参数一)发来的消息,原理为调用recv,通过socket找到协议的缓冲区,并把数据拷贝进参数二(用户自己设置的缓冲区)

intrecv( SOCKET s, char * buf, int len, int flags ); // recv接收消息过程是阻塞的

参数一:客户端的socket

参数二:接收消息的存储空间(协议规定网络最大传输单元为1500字节)

参数三:想要读取的字节数,一般为参数二字节数减一

参数四:一般为0:表示将协议缓冲区中的数据拷贝到我们的Buf中,然后协议的缓冲区就删除这一部分已拷贝的数据(读出来就删除)

​ MSG_PEEK:数据被复制到Buf中,但不会从协议的缓冲区中删除

​ MSG_OOB:传输一段数据,在外带一个额外的特殊数据

​ MSG_WAITALL:知道协议的缓冲区中数据的字节数满足参数三请求的字节数,才开始读取

返回值:读出来的字节数大小,若客户端下线,返回0,若执行失败,返回SOCKET_ERROR

int nlen = recv(cSock, recvBuf, 128, 0);if (nlen == 0){cout << "客户端退出..." << endl;}

发送消息:向目标发送数据,send函数将我们的数据复制进系统的协议发送缓冲区中,然后系统发送出去,最大传输单元1500字节

intsend( SOCKET s, const char * buf, int len, int flags );

参数一:目标的socket

参数二:给对方发送的数据

参数三:字节个数

惨数四:一般为0,表示正常的发送

​ MSG_OOB:意义同recv

​ MSG_DONTROUTE:指定数据应不受路由限制

返回值:成功则返回写入的字节数,失败返回SOCKET_ERROR

send(cSock, msg.c_str(), msg.length(), 0);

服务端代码:

#define WIN32_LEAN_AND_MEAN#include <iostream>#include <thread>#include <vector>#include <WinSock2.h>#pragma comment(lib, "ws2_32.lib")using namespace std;int main(){// 启动Windows socket2 环境//初始化套节字WORD ver = MAKEWORD(2, 2);WSADATA dat;WSAStartup(ver, &dat);// 校验版本if (2 != HIBYTE(dat.wVersion) || 2 != LOBYTE(dat.wVersion)){// 版本不对WSACleanup();return 0;}//1 建立一个socketSOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);sockaddr_in sin = {};sin.sin_family = AF_INET;sin.sin_port = htons(4567);sin.sin_addr.S_un.S_addr = inet_addr("192.168.1.4");//2 bind 绑定用于接受客户端链接的网络端口if (SOCKET_ERROR == bind(sock, (sockaddr*)&sin, sizeof(sin))){cout << "绑定网络端口失败" << endl;}else {cout << "绑定网络端口成功" << endl;}//3. listen监听网络端口if (SOCKET_ERROR == listen(sock, 5)){cout << "监听网络端口失败" << endl;}else {cout << "监听网络端口成功" << endl;}//4 accept 等待客户端链接sockaddr_in clientAddr = {};int nAddrLen = sizeof(sockaddr_in);SOCKET cSock = INVALID_SOCKET;string msg = "Hello, I'm Server";cSock = accept(sock, (sockaddr*)&clientAddr, &nAddrLen);if (INVALID_SOCKET == cSock){cout << "错误,接受到无效客户端SOCKET..." << endl;}cout << "新客户端加入:" << inet_ntoa(clientAddr.sin_addr) << endl;//5 send 向客户端发送数据char recvBuf[128] = {};while (true){int nlen = recv(cSock, recvBuf, 128, 0);if (nlen <= 0){cout << "客户端退出..." << endl;break;}send(cSock, msg.c_str(), msg.length(), 0);}//6 关闭套接字closesocketclosesocket(sock);//清楚Windows socket环境WSACleanup();} 客户端

打开网络库

校验版本

创建socket

连接到服务器

intconnect( SOCKET s, const struct sockaddr * name, int namelen );

作用:连接服务器并将服务器信息与服务器socket绑定到一起

参数一:服务器socket

参数二:服务器IP地址和端口号的结构体

参数三:参数二结构体大小

返回值:成功返回0,失败返回SOCKET_ERROR

与服务器收发消息

客户端代码:

#define WIN32_LEAN_AND_MEAN#include <iostream>#include <thread>#include <vector>#include <WinSock2.h>#pragma comment(lib, "ws2_32.lib")using namespace std;int main(){// 启动Windows socket2 环境//初始化套节字WORD ver = MAKEWORD(2, 2);WSADATA dat;WSAStartup(ver, &dat);//1 创建一个socketSOCKET sock = socket(AF_INET, SOCK_STREAM, 0);if (INVALID_SOCKET == sock){cout << "错误,建立socket失败" << endl;}else{cout << "建立socket成功.." << endl;}//2 连接服务器sockaddr_in sin = {};sin.sin_family = AF_INET;sin.sin_port = htons(4567);sin.sin_addr.S_un.S_addr = inet_addr("192.168.1.4");if (SOCKET_ERROR == connect(sock, (sockaddr*)&sin, sizeof(sockaddr_in))){cout << "建立连接失败..." << endl;}else {cout << "建立连接成功..." << endl;}//3 接收服务器信息char recvBuf[256] = {};int nlen = recv(sock, recvBuf, 256, 0);if (nlen > 0){cout << "接受到数据:" << recvBuf << endl;}//4 关闭套节字closesocketclosesocket(sock);getchar();//清楚Windows socket环境WSACleanup();}

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。