现在,我们通过accept()创建了新的socket,也就是我们类中的数据成员communicationSock,现在,我们就可以通过这个socket进行通讯了。
TCP通讯模型
在介绍函数之前,我们应该了解一些事实。TCP的Server/Client模型类似这样:
ServApp——ServSock——Internet——ClntSock——ClntApp
当然,我们这里的socket指的就是用于“通讯”的socket。TCP的server端至少有两个socket,一个用于监听,一个用于通讯;TCP的server端可以只有一个socket,这个socket同时“插”在server的两个socket上。当然,插上listen socket的目的只是为了创建communication socket,创建完备后,listen是可以关闭的。但是,如果这样,其他的client就无法再连接上server了。
我们这个模型,是client的socket插在server的communication socket上的示意。这两个socket,都拥有完整的本地地址信息以及远程计算机地址信息,所以,这两个socket以及之间的网络实际上形成了一条形式上“封闭”的管道。数据包只要从一端进来,就能知道出去的目的地,反之亦然。这正是TCP协议,数据流形式抽象化以及实现。因为不再需要指明“出处”和“去向”,对这样的socket(实际上是S/C上的socket对)的操作,就如同对本地文件描述符的操作一样。但是,尽管我们可以使用read()和write(),但是,为了完美的控制,我们最好使用recv()和send()。
recv()和send()
- int send(int socket, const void* msg, unsigned int msgLength, int flags);
- int recv(int socket, void* rcvBuffer, unsigned int bufferLength, int flags);
在Linux中的实现为:
- #include <sys/socket.h>
- /* Send N bytes of BUF to socket FD. Returns the number sent or -1.
- This function is a cancellation point and therefore not marked with
- __THROW. */
- extern ssize_t send (int __fd, __const void *__buf, size_t __n, int __flags);
- /* Read N bytes into BUF from socket FD.
- Returns the number read or -1 for errors.
- This function is a cancellation point and therefore not marked with
- __THROW. */
- extern ssize_t recv (int __fd, void *__buf, size_t __n, int __flags);
这两个函数的第一个参数是用于“通讯”的socket,第二个参数是发送或者接收数据的起始点指针,第三个参数是数据长度,第四个参数是控制符号(默认属性设置为0就可以了)。失败时候传回-1,否则传回实际发送或者接收数据的大小,返回0往往意味着连接断开了。
处理echo行为
- void TcpServer::handleEcho()
- {
- const int BUFFERSIZE = 32;
- char buffer[BUFFERSIZE];
- int recvMsgSize;
- bool goon = true;
- while ( goon == true ) {
- if ( (recvMsgSize = recv(communicationSock, buffer, BUFFERSIZE, 0)) < 0 ) {
- throw "recv() failed";
- } else if ( recvMsgSize == 0 ) {
- goon = false;
- } else {
- if ( send(communicationSock, buffer, recvMsgSize, 0) != recvMsgSize ) {
- throw "send() failed";
- }
- }
- }
- close(communicationSock);
- }
本小节最后要讲的函数是close(),它包含在<unistd.h>中
- #include <unistd.h>
- /* Close the file descriptor FD.
- This function is a cancellation point and therefore not marked with
- __THROW. */
- extern int close (int __fd);
这个函数用于关闭一个文件描述符,自然,也就可以用于关闭socket。
下一小节是完整的源代码。默认的监听端口是5000。我们可以通过
$telnet 127.0.0.1 5000
验证在本机运行的echo server程序。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。