网络编程是指人们利用套接字来实现通信不同计算机之间的互传文件,聊天,图像等,要学习网络编程首先要了解网络基础知识。
(一)先介绍OSI七层网络模型。
物理硬件层:表示计算机网络中的物理设备。常见的有网卡。
数据链路层:将传输的数据进行压缩和解压缩。
网络层: 将要传输的数据进行网络传输。
数据传输层:进行信息的网络传输。
会话层: 建立物理网络的连接。
表示层: 将传输的数据以某种格式进行表示。
应用层: 应用程序接口。
(2)TCP/IP协议
TCP/IP协议实际上是一个协议簇,其中包括了很多协议,例如FTP(文件传输协议)、SMAP(邮电传输协议)等应用层协议。TCP/IP协议的网络模型只有4层,包括数据链路层、网络层、数据传输层和应用层。
数据链路层: 网卡等网络硬件设备以及驱动设备。
网络层: IP协议等互联协议。
数据传输层: 为应用程序提供通信方法,通常为TCP、UDP.
应用层: 负责处理应用程序的实际应用层协议。
这里介绍一下TCP协议与UDP协议的去区别。
TCP协议是基于面向连接的可靠通信协议,它具有重发机制,通俗来说,它就像打电话,必须双方接通后才能通信,也称为流式套接字。
UDP协议是基于用户数据报协议,属于不可靠无连接协议. 就像发短信,不知道对方收到没有,也可能丢失。
(三)C/S模型 是基于可靠连接的通信模型。通信双方必须使用各自的IP地址以及端口号进行通信。通信的一方叫客户端,一方叫服务器端。
下面简单拿程序来介绍C/S模型,与网络编程。
服务器端 客户端
加载套接字 加载套接字
创建套接字 创建套接字
绑定套接字 绑定套接字
监听
连接 连接
通信 通信
关闭套接字 关闭套接字
在vs中编写服务器端如下:
#include<stdio.h>
#include<WinSock2.h>//windows socket套接字库
#pragma comment(lib, "ws2_32.lib")
int main()
{
printf("***********************************\n");
printf("*******欢迎使用QQ聊天系统服务器*******\n");
//1.加载套接字库
WSADATA wsaData;
//返回0:成功了; 返回非0 :失败了;
int nErr = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (0 != nErr)
{
printf("加载套接字库失败.\n");
return 0;
}
//判断版本对不对2.2 高地位
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion)!=2)
{
printf("加载套接字库版本不一致.\n");
return 0;
}
//2创建套接字
/*
流式套接字:TCP(传控制协议)(面向连接的)先连接 打电话
数据报套接字:UDP(用户数据报协议) 不需要先建立连接 写信
*/
SOCKET sockSrv = socket(
AF_INET,//地址族
SOCK_STREAM,//套接字类性
0 //会根据地址格式和套接字的类ixng,自动选择合适的协议
);
//绑定套接字
sockaddr_in addrSrv;
addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(9527);// 0-65535
//绑定套接字
if (SOCKET_ERROR == bind(
sockSrv,
(sockaddr*)&addrSrv,
sizeof(sockaddr)
))
{
printf("绑定套接字失败\n");
return 0;
}
if (SOCKET_ERROR == listen(sockSrv, 5))//监听失败
{
printf("监听失败.\n");
return 0;
}
//客户端的地址信息
SOCKADDR_IN addrClient;
int nLength = sizeof(addrClient);
while (1)
{
//等待客户的请求,接受请求
SOCKET sockConn=accept(sockSrv,//服务器套接字
(sockaddr*)&addrClient,//客户端的地址信息
&nLength //客户端的地址信息大小
);
printf("欢迎客户端:%s:%d连接服务器.\n", inet_ntoa(addrClient.sin_addr),
addrClient.sin_port);
while (1)
{
printf("请输入待发送的信息【按q退出】\n");
char szSendMsg[100];
scanf("%s",szSendMsg);
if (strcmp(szSendMsg, "q") == 0)
{
printf("已经与客户端断开连接.\n");
closesocket(sockConn);
break;
}
send(sockConn, szSendMsg, strlen(szSendMsg) + 1, 0);
char szRecvMsg[100];
recv(sockConn, szRecvMsg, 100, 0);
printf("服务器说:%s", szRecvMsg);
printf("\n");
}
}
WSACleanup();
getchar();
return 0;
}
编写客户端如下:
#include<stdio.h>
#include<WinSock2.h>//windows socket套接字库
#pragma comment(lib, "ws2_32.lib")
int main()
{
printf("***********************************\n");
printf("*******欢迎使用QQ聊天系统客户端*******\n");
//1.加载套接字库
WSADATA wsaData;
//返回0:成功了; 返回非0 :失败了;
int nErr = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (0 != nErr)
{
printf("加载套接字库失败.\n");
return 0;
}
//判断版本对不对2.2 高地位
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
{
printf("加载套接字库版本不一致.\n");
return 0;
}
//2创建套接字
/*
流式套接字:TCP(传控制协议)(面向连接的)先连接 打电话
数据报套接字:UDP(用户数据保协议) 不需要先建立连接 写信
*/
SOCKET sockClient = socket(
AF_INET,//地址族
SOCK_STREAM,//套接字类性
0 //会根据地址格式和套接字的类ixng,自动选择合适的协议
);
//连接服务器
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr =inet_addr("172.16.12.219");
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(9527);// 0-65535
if (SOCKET_ERROR == connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR)))
{
printf("连接服务器失败.\n");
return 0;
}
//发送
//send
//接收
//recv
while (1)
{
char szRecvMsg[100];
recv(sockClient, szRecvMsg, 100, 0);
printf("服务器说:%s", szRecvMsg);
printf("\n");
printf("请输入待发送的信息【按q退出】:\n");
char szSendMsg[100];
scanf("%s", szSendMsg);
if (strcmp(szSendMsg, "q") == 0)
{
printf("已经与服务器端断开联系了.\n");
closesocket(sockClient);
break;
}
send(sockClient, szSendMsg, strlen(szSendMsg) + 1, 0);
}
//关闭套接字库
WSACleanup();
return 0;
}
运行结果如下: