网络编程socket的helloworld
首先要创造一个套接字,套接字有三种类型,流套接字(SOCK_STREAM)、数据报套接字(SOCK_DGRAM)、原始套接字(SOCKE_RAM)
流套接字就是用TCP协议的套接字,数据报套接字就是用UDP协议的套接字,原始套接字可以读取网际层的协议。
SOCKET socket(int af,int type,int protocol);
// 第一个参数af为开头为AF_的宏,用于设定地址簇,AF_是BSD系统网络编程常用的宏的开头,PF_是POSIX系统网络编程常用的宏的开头,
// 这两个开头的宏的意思一样,windows是为了致敬前人才这么写的
// AF_INET ipv4地址
// AF_INET6 ipv6地址
// AF_UNIX 用本地套接字
// 第二个参数type为套接字类型,分别有流套接字(SOCK_STREAM)、数据报套接字(SOCK_DGRAM)、原始套接字(SOCK_RAM),可靠地连续数据包服务(SOCK_SEQPACKET)
// 第三个参数protocol为用的协议,传0意味着不指定协议,让写这个函数的人帮你选择
接着是写套接字地址,套接字地址是一个数据结构,包含ip地址和端口号,对于ipv4的地址,用
typedef struct sockaddr_in {
ADDRESS_FAMILY sin_family; // 地址簇,用AF_INET就行
USHORT sin_port; // 端口号
IN_ADDR sin_addr; // ip地址
CHAR sin_zero[8]; // 这个不知道是啥
} SOCKADDR_IN, *PSOCKADDR_IN;
网络字节序是大端存储,也就是高位的字节在首地址的位置,例如0xabcd,大端存储就是ab cd,小端存储就是cd ab,所以进行网络传输的套接字地址也是大端存储,但是计算机存储方式可能是小端存储,这时候就需要进行转换。
unsigned short htons(unsigned short hosts);// 这个函数将一个16位的数据转化为大端字节序 host to net short
unsigned long htonl(unsigned long hostl);// 这个函数将一个32位的数据转化为大端字节序 host to net long
unsigned short ntohs(unsigned short nets);// 这个函数将一个16位的大端字节序数据转化为主机上用的字节序数据 net to host short
unsigned long ntohl(unsigned long netl);// 这个函数将一个32位的大端字节序数据转化为主机上用的字节序数据 net to host long
服务器端要做的功能是绑定ip地址,创建端口号,然后监听访问这个ip地址这个端口号的另一个信息,最后接受这个信息,反正我就这么理解了。
所以服务器端的写法是:绑定(bind),监听(listen),接受(accept)
int bind(SOCKET s,const struct sockaddr* name,int namelen);
// 这个函数第一个参数是套接字类型,第二个参数是套接字地址,第三个参数是套接字地址的长度
// 要注意能绑定的ip地址只能是这台计算机所在的网络中存在的ip地址,如果绑定到无效的ip地址就会报错
int listen(SOCKET s,int backlog);
// 第一个参数是服务器套接字,第二个参数是请求队列能容纳的最大长度,也就是说能允许多少台计算机同时访问
SOCKET accept(SOCKET s,struct sockaddr* addr,int* addrlen);
// 第一个参数为创建出来的套接字也就是服务器的套接字,第二个参数为要接收到客户端套接字地址的变量的首地址,第三个参数为要存放接收到的套接字的长度的变量的首地
客户端要做的是连接到服务器,所以客户端只需要写连接(connect)就行
int connect(SOCKET s,const struct sockaddr* name,int namelen);
// 第一个参数是还没有连接的套接字,第二个参数是服务器端的套接字地址,第三个参数是存放服务器端套接字地址的长度
在服务器端和客户端与对面交流用send();和recv();两个函数
int send(SOCKET s,const char* buf,int len,int flags);
// 第一个参数是客户端套接字
// 第二个参数是要发送的信息
// 第三个参数是信息的长度,以字节为单位
// 第四个参数是发送的方法,设为0即可
int recv(SOCKET s,char* buf,int len,int flags);
// 第一个参数是客户端套接字,第二个参数是要接收信息的变量的首地址,第三个参数是要接收信息的变量的容量,第四个参数设为0
服务器端:
#include<WinSock2.h> #include<Windows.h> #include<strsafe.h> #pragma comment(lib,"Ws2_32.lib") int main() { WSAData wsa; WSAStartup(MAKEWORD(2, 2), &wsa); SOCKET serveSocket = socket(AF_INET, SOCK_STREAM, 0); sockaddr_in serveAddress; serveAddress.sin_addr.S_un.S_addr = htonl(ADDR_ANY); serveAddress.sin_family = AF_INET; serveAddress.sin_port = htons(6000); bind(serveSocket, (sockaddr*)&serveAddress, sizeof(serveAddress));// 绑定 listen(serveSocket, 1);// 监听 sockaddr_in clientAddress; int clientlen = sizeof(clientAddress); SOCKET clientSocket=accept(serveSocket, (sockaddr*)&clientAddress, &clientlen);// 接受 char recvBuf[128]; int retv=recv(clientSocket, recvBuf, 128, 0); if (retv > 0) { printf("%s", recvBuf); } else if (retv == 0) { printf("连接已断开"); } else { WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), L"出故障了", 5, NULL, NULL); wchar_t ErrorBuf[128]; StringCchPrintfW(ErrorBuf, 128, L"错误码:%d\n", GetLastError()); size_t szlen; StringCchLengthW(ErrorBuf, 128, &szlen); WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ErrorBuf, szlen, NULL, NULL); getchar(); closesocket(clientSocket); closesocket(serveSocket); WSACleanup(); return 0; } char sendBuf[128]; sprintf(sendBuf, "你发来的消息是:%s\0", recvBuf); send(clientSocket, sendBuf, strlen(sendBuf)+1, 0); getchar(); closesocket(clientSocket); closesocket(serveSocket); WSACleanup(); return 0; }
客户端:
#include<WinSock2.h> #include<strsafe.h> #pragma comment(lib,"Ws2_32.lib") int main() { WSAData wsa; WSAStartup(MAKEWORD(2, 2), &wsa); SOCKET clientSocket = socket(AF_INET, SOCK_STREAM, 0); sockaddr_in serveAddress; serveAddress.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); serveAddress.sin_port = htons(6000); serveAddress.sin_family = AF_INET; if (SOCKET_ERROR == connect(clientSocket, (sockaddr*)&serveAddress, sizeof(serveAddress))) { printf("连接到服务器失败"); getchar(); return 0; } char sendBuf[128]; printf("请输入要发送的信息:"); scanf("%s", sendBuf); send(clientSocket, sendBuf, strlen(sendBuf)+1, 0); recv(clientSocket, sendBuf, 128, 0); printf("%s", sendBuf); getchar(); getchar(); closesocket(clientSocket); WSACleanup(); return 0; }