流式套接字实现简单的客户端/服务端通信过程
一、 实验内容
- 熟悉流式套接字socket函数的使用方法,包括建立连接、数据发送/接收和关闭连接等;
- 客户端可向服务端发送任意字符串,服务端在接收到该字 符串后,回送给客户端;(此过程可循环)
- 服务端在接收到新连接后,能够打印出客户端的ip和端口;(如何获取连接套接字上的地址信息,请自行查阅资料)
- 服务端采用多线程模式,能够同时接收多个客户端的连接请求,为每个客户端连接开启一个线程;(多线程编程自行查阅资料)
二、 实验要求
提交源码(源码编写要规范)、可执行程序、实验报告(要有程序运行截图)。
三、 实验分析
Server
(1)函数
- 初始化──WSAStartup():此函数在应用程序中初始化Windows Sockets DLL,只有此函数调用成功后,应用程序才可以再调用其他的API函数。
int WSAStartup(
WORD wVersionRequested,// 所使用的WinSocket版本LPWSADATA lpWSAData// 存数系统返回的WinSocket信息);
- 创建套接字──socket() :初始化WinSock的动态链接库后,需要在服务器端建立一个Socket,为此可以调用socket()函数来建立这个监听的Socket,并定义此Socket所使用的通信协议。
SOCKET socket(
int af,
// 目前只提供PF_INET(AF_INET)
int type,
// Socket的类型(SOCK_STREAM、SOCK_DGRAM)
int protocol,
// 通讯协议(如果使用者不指定,则设为0)
);
- 指定本地地址──bind():客户端这样才能够知道要连接到何处,该函数调用成功返回0,否则返回SOCKET_ERROR。
bind(
_In_ SOCKET s,// Socket对象名
_In_reads_bytes_(namelen) const struct sockaddr FAR * name,//结构体 Socket的地址值,即所在及其的IP地址
_In_ int namelen
);
//调用bind()函数之后,为socket()函数创建的套接字关联一个相应地址,发送到这个地址
- 监听信息──listen()
int listen(SOCKET s,
// 需要建立监听的Socketint backlog,
// 最大连接个数);
- 等待接受信息──accpet()
accept(
_In_ SOCKET s,
_Out_writes_bytes_opt_(*addrlen) struct sockaddr FAR * addr,
_Inout_opt_ int FAR * addrlen
);
- 数据传送与接收──send()与recv()
int recv(
SOCKET s,// Socket的识别码
char FAR *buf,// 存放接收到的数据的缓存区
int len,// buf的长度
int flags// 此函数被调用的方式);
int send(SOCKET s,// Socket的识别码const char FAR *buf,// 存放要传送的数据的缓存区int len, // buf的长度int flags// 此函数被调用的方式);
- 结束──closesocket()
int closesocket(SOCKET s;
// Socket的识别码);
(2)多线程的实现
利用函数CreateThread实现
CreateThread(
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ SIZE_T dwStackSize,
_In_ LPTHREAD_START_ROUTINE lpStartAddress,加载函数地址
_In_opt_ __drv_aliasesMem LPVOID lpParameter,加载函数参数
_In_ DWORD dwCreationFlags,
_Out_opt_ LPDWORD lpThreadId
);
DWORD WINAPI ClientThread(LPVOID lpParameter)
{
SOCKET CientSocket = (SOCKET)lpParameter;
int Ret = 0;
int Ret1 = 0;
char</