Socket原理-TCP三次握手代码参考:
https://blog.csdn.net/panker2008/article/details/46502783
Server(服务端)
#include <winsock2.h>
#include <stdio.h>
#include <time.h>
int main()
{
// 数据缓冲变量准备
char sendBuf[100]; //发送信息
int turn = 0; //数据是否发送完毕,1表示完毕,0表示未发送完毕
char receiveBuf[100];//接收
int stime, etime, timeout; //超时计时器
// 初始化,初始化后进去监听状态
// 创建套接字,socket前的一些检查工作,包括服务的启动
WORD myVersionRequest;
WSADATA wsaData;
myVersionRequest = MAKEWORD(1,1);
int err;
err = WSAStartup(myVersionRequest,&wsaData);
if (!err)
{
printf("Socket has openned...\n");
}
else
{
//进一步绑定套接字
printf("Socket doesn't open...");
return 0;
}
SOCKET serSocket = socket(AF_INET,SOCK_STREAM,0);//创建了可识别套接字
//需要绑定的参数,主要是本地的socket的一些信息。
SOCKADDR_IN addr;
addr.sin_family = AF_INET;
addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//ip地址
addr.sin_port = htons(6000);//绑定端口
bind(serSocket,(SOCKADDR*)&addr,sizeof(SOCKADDR));//绑定完成
listen(serSocket,5);//监听,其中第二个参数代表能够接收的最多的连接数
SOCKADDR_IN clientsocket;
int len = sizeof(SOCKADDR);
// 连接对象
SOCKET serConn;
//第二次握手,通过accept来接受对方的套接字的信息
serConn = accept(serSocket,(SOCKADDR*)&clientsocket,&len);//如果这里不是accept而是conection的话,就会不断的监听
sprintf(sendBuf,"welcome %s to Sunking's Service!",inet_ntoa(clientsocket.sin_addr));//找对对应的IP并且将这行字打印到那里
send(serConn,sendBuf,strlen(sendBuf)+1,0);
// 计时器启动
stime = time(0);
timeout = 0;
// 交互模块
while(1){
// 10s超时后,执行和新用户的第二次握手,通过accept来接受对方的套接字的信息
if(timeout > 10){
printf("\nwait client to connect...");
printf("\n");
serConn = accept(serSocket,(SOCKADDR*)&clientsocket,&len);//如果这里不是accept而是conection的话,就会不断的监听
sprintf(sendBuf,"welcome %s to Sunking's Service!",inet_ntoa(clientsocket.sin_addr));//找对对应的IP并且将这行字打印到那里
send(serConn,sendBuf,strlen(sendBuf)+1,0);
}
// 接受第三次握手发来的消息
memset(receiveBuf, '\0', strlen(receiveBuf)+1);
recv(serConn,receiveBuf,strlen(receiveBuf)+1,0);
if (strlen(receiveBuf) == 0 && turn)
{
turn = 0;
// 成功接收完客户端发来的消息
sprintf(sendBuf, "receive successfully!\n");
send(serConn,sendBuf,strlen(sendBuf)+1,0);
printf("\nFinish to receive client's data, wait...\n");
}else if(strlen(receiveBuf) != 0 && !turn){
stime = time(0); // 若开始收到来自client的消息,刷新开始时间
turn = 1;
}// 否则什么也不做
printf("%s",receiveBuf);
// 计时
etime = time(0);
timeout = etime - stime;
}
closesocket(serConn);//关闭
WSACleanup();//释放资源的操作
return 0;
}
Client(客户端)
#include <winsock2.h>
#include <stdio.h>
int main()
{
//SOCKET前的一些检查,检查协议库的版本,为了避免别的版本的socket,并且通过
//WSAStartup启动对应的版本,WSAStartup的参数一个是版本信息,一个是一些详细的细节,注意高低位
//WSAStartup与WSACleanup对应
int err;
WORD versionRequired;
WSADATA wsaData;
versionRequired = MAKEWORD(1,1);
err = WSAStartup(versionRequired,&wsaData);//协议库的版本信息
//通过WSACleanup的返回值来确定socket协议是否启动
if (!err)
{
printf("Client socket has openned...\n");
}
else
{
printf("Client socket is failed to open...\n");
return 0;//结束
}
//创建socket这个关键词,这里想一下那个图形中的socket抽象层
//注意socket这个函数,他三个参数定义了socket的所处的系统,socket的类型,以及一些其他信息
SOCKET clientSocket = socket(AF_INET,SOCK_STREAM,0);
//socket编程中,它定义了一个结构体SOCKADDR_IN来存计算机的一些信息,像socket的系统,
//端口号,ip地址等信息,这里存储的是服务器端的计算机的信息
SOCKADDR_IN clientsock_in;
clientsock_in.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");// 127.0.0.1本地自回路
clientsock_in.sin_family = AF_INET;
clientsock_in.sin_port = htons(6000);
//前期定义了套接字,定义了服务器端的计算机的一些信息存储在clientsock_in中,
//准备工作完成后,然后开始将这个套接字链接到远程的计算机
//也就是**第一次握手**
connect(clientSocket,(SOCKADDR*)&clientsock_in,sizeof(SOCKADDR));//开始连接
// 接受第二次握手发来的消息
char receiveBuf[100];
//解释socket里面的内容
recv(clientSocket,receiveBuf,101,0);
printf("%s\n",receiveBuf);
//发送socket数据,第三次握手
char sendBuf[100];
sprintf(sendBuf,"\nClient successfully connect!\n");
send(clientSocket,sendBuf,strlen(sendBuf)+1,0);
// 用户向服务器发送信息
char quit[100];
while(1){
printf(">> Send data?(q or Q to quit): ");
// 用户请求
gets(quit);
// 用户结束访问
if (quit[0] == 'q' || quit[0] == 'Q' && quit[1] == '\0'){
break;
}
// 用户输入数据
printf("\n>> Input your data: ");
gets(sendBuf);
send(clientSocket,sendBuf,strlen(sendBuf)+1,0);
// 数据接收成功判断
while(1){
memset(receiveBuf, '\0', strlen(receiveBuf)+1);
recv(clientSocket,receiveBuf,strlen(receiveBuf)+1,0);
if (strlen(receiveBuf) == 0)
{
break;
}
printf("%s", receiveBuf);
}
}
//关闭套接字
closesocket(clientSocket);
//关闭服务
WSACleanup();
return 0;
}
运行方式(本人是win10的cmd下执行)
执行过程:
- client.exe:
gcc -o client client.c MinGW绝对路径\lib\libws2_32.a MinGW绝对路径\lib\libwsock32.a- server.exe:
gcc -o server server.c MinGW绝对路径\lib\libws2_32.a MinGW绝对路径\lib\libwsock32.a- 先运行server,server进入监听状态,再运行client,三次握手完成TCP建立;
- 按照提示从客户端向服务器端传输字符串(客户端用户10s不传输,会默认超时,若客户端关闭可重新打开新的客户端建立连接,否则正常执行)
结果: