参考:
最近笔试遇到一个选择题,说在Linux进行Socket通信的时候那个阶段不会阻塞。由于没有接触过这方面的内容,通过查找一些资料进行学习。
socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作。Socket就是该模式的一个实现, socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭).
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。它把复杂的TCP/IP协议隐藏在Socket接口后,对用户来说一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
服务器端需要创建Socket,绑定地址,进行监听。
客户端需要创建Socket,建立连接(指定地址),然后进行数据交互。
流程图如下:
C++的连接用send发送数据,recv接收数据。
// Server.cpp
#include <stdio.h>
#include <winsock2.h>
int main()
{
WORD sockVersion = MAKEWORD(2, 2);
WSADATA wsaData;
// 初始化WSA
if (WSAStartup(sockVersion, &wsaData) != 0)
{
return 0;
}
/**
AF_INET Arpa(TCP/IP) 网络通信协议(IPV4)
AF_INET6 IPV6
AF_UNIX UNIX 域协议(文件系统套接字)(或称AF_LOCAL ,Unix域socket)
AF_ISO ISO标准协议
AF_NS 施乐网络体统协议
AF_IPX Novell IPX 协议
AF_APPLETALK Appletalk DDS
AF_ROUTE 路由套接字
AF_KEY 密钥套接字
*/
//创建套接字
SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (slisten == INVALID_SOCKET)
{
printf("socket error!");
return -1;
}
// 绑定IP和端口
sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(8888);
sin.sin_addr.S_un.S_addr = INADDR_ANY;
if (bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
{
printf("bind error!");
}
//开始监听
if (listen(slisten, 5) == SOCKET_ERROR)
{
printf("listen error!");
}
// 循环接受数据
SOCKET sClient;
sockaddr_in remoteAddr;
int nAddrlen = sizeof(remoteAddr);
char revData[255];
while (true)
{
printf("\nWaiting for connect...\n");
sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);
if (sClient == INVALID_SOCKET)
{
printf("accept error !");
continue;
}
printf("\nACCEPT an connection: %s \r\n", inet_ntoa(remoteAddr.sin_addr));
//接收数据
int ret = recv(sClient, revData, 255, 0);
if (ret > 0)
{
revData[ret] = 0x00;
printf(revData);
}
//发送数据
const char *sendData = "\nHello,TCP clinet!\n";
send(sClient, sendData, strlen(sendData), 0);
closesocket(sClient);
}
closesocket(slisten);
WSACleanup();
return 0;
}
// Clinet.cpp
#include <WINSOCK2.H>
#include <STDIO.H>
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
#pragma comment(lib, "ws2_32.lib")
int main()
{
WORD sockVersion = MAKEWORD(2, 2);
WSADATA data;
if (WSAStartup(sockVersion, &data) != 0)
{
return 0;
}
while (true)
{
// 创建SOCKET
SOCKET sclient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sclient == INVALID_SOCKET)
{
printf("invalid socket!");
return 0;
}
sockaddr_in serAddr;
serAddr.sin_family = AF_INET;
serAddr.sin_port = htons(8888);
serAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
if (connect(sclient, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR)
{ //连接失败
printf("connect error !");
closesocket(sclient);
return 0;
}
string data;
std::cin >> data;
const char *sendData;
sendData = data.c_str(); //string转const char*
//char * sendData = "你好,TCP服务端,我是客户端\n";
send(sclient, sendData, strlen(sendData), 0);
//send()用来将数据由指定的socket传给对方主机
//int send(int s, const void * msg, int len, unsigned int flags)
//s为已建立好连接的socket,msg指向数据内容,len则为数据长度,参数flags一般设0
//成功则返回实际传送出去的字符数,失败返回-1,错误原因存于error
char recData[255];
int ret = recv(sclient, recData, 255, 0);
if (ret > 0)
{
recData[ret] = 0x00;
printf(recData);
}
closesocket(sclient);
}
WSACleanup();
return 0;
}