1 基于套接字的进程间通信
2 基于套接字的网络通信
3 基于TCP协议的客户机与服务器
1 基于套接字的进程间通信
1.1 问题
套接字(socket)是一个基于TCP/IP协议可实现基本网络通信功能的逻辑对象。机器与机器的通信,或者进程与进程的通信,在这里都可以被抽象地看作是套接字与套接字的通信。应用程序编写者无需了解网络协议的任何细节,更无需知晓系统内核和网络设备的运作机制,只要把想发送的数据写入套接字,或从套接字中读取想接收的数据即可。从这个意义上讲,套接字就相当于一个文件描述符,而网络就是一种特殊的文件,面向网络的编程与面向文件的编程已没有分别,而这恰恰是Unix系统一切皆文件思想的又一例证。
1.2 步骤
实现此案例需要按照如下步骤进行。
步骤一:服务器
代码如下所示:
#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int sockfd = socket (AF_LOCAL, SOCK_DGRAM, 0);
if (sockfd == -1)
{
perror (“socket”);
exit (EXIT_FAILURE);
}
struct sockaddr_un addr;
addr.sun_family = AF_LOCAL;
strcpy (addr.sun_path, “mysock”);
if (bind (sockfd, (struct sockaddr*)&addr, sizeof (addr)) == -1)
{
perror (“bind”);
unlink(“mysock”);
exit (EXIT_FAILURE);
}
char text[1024];
ssize_t readed = read (sockfd, text, 1024);
if (readed == -1)
{
perror (“read”);
unlink(“mysock”);
exit (EXIT_FAILURE);
}
printf(“客户机发送内容:%s\n”, text);
if (close (sockfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
unlink(“mysock”);
return 0;
}
上述代码中,以下代码:
int sockfd = socket (AF_LOCAL, SOCK_DGRAM, 0);
if (sockfd == -1)
{
perror (“socket”);
exit (EXIT_FAILURE);
}
使用函数socket创建套接字,该函数有三个参数,说明如下:
第一个参数为通信域,即协议族,可取以下值:
AF_LOCAL/AF_UNIX - 本地通信,即进程间通信
AF_INET - 基于IPv4的网络通信
AF_INET6 - 基于IPv6的网络通信
AF_PACKET - 基于底层包接口的网络通信
第二个参数为套接字类型,可取以下值
SOCK_STREAM - 流式套接字,即使用TCP协议的套接字
SOCK_DGRAM - 数据报套接字,即使用UDP协议的套接字
SOCK_RAW - 原始套接字,即使用IP协议的套接字
第三个参数为特殊协议,通常不用,取0即可。
上述代码中,以下代码:
struct sockaddr_un addr;
addr.sun_family = AF_LOCAL;
strcpy (addr.sun_path, “mysock”);
准备地址结构,使用sockaddr_un结构体类型。
上述代码中,以下代码:
if (bind (sockfd, (struct sockaddr*)&addr, sizeof (addr)) == -1)
{
perror (“bind”);
unlink(“mysock”);
exit (EXIT_FAILURE);
}
使用函数bind将套接字对象和自己的地址结构绑定在一起,该函数有三个参数,说明如下:
第一个参数为套接字描述符。
第二个参数为自己的地址结构。
第三个参数为地址结构长度(以字节为单位)。
上述代码中,以下代码:
char text[1024];
ssize_t readed = read (sockfd, text, 1024);
if (readed == -1)
{
perror (“read”);
unlink(“mysock”);
exit (EXIT_FAILURE);
}
printf(“客户机发送内容:%s\n”, text);
使用函数read通过套接字接收字节流。该函数有三个参数,说明如下:
第一个参数为套接字描述符
第二个参数为内存缓冲区
第三个参数为期望读取的字节数
上述代码中,以下代码:
if (close (sockfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
使用函数close关闭处于打开状态的套接字描述符,该函数的参数为处于打开状态的套接字描述符。
上述代码中,以下代码:
unlink("mysock");
使用函数unlink删除不再使用的套接字文件。
步骤二:客户端
代码如下所示:
#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int sockfd = socket (AF_LOCAL, SOCK_DGRAM, 0);
if (sockfd == -1)
{
perror (“socket”);
exit (EXIT_FAILURE);
}
struct sockaddr_un addr;
addr.sun_family = AF_LOCAL;
strcpy (addr.sun_path, “mysock”);
if (connect (sockfd, (struct sockaddr*)&addr, sizeof (addr)) == -1)
{
perror (“connect”);
exit (EXIT_FAILURE);
}
char text[1024] = “你好,服务器”;
ssize_t written = write (sockfd, text, strlen(text));
if (written == -1)
{
perror (“write”);
exit (EXIT_FAILURE);
}
if (close (sockfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
上述代码中,以下代码:
int sockfd = socket (AF_LOCAL, SOCK_DGRAM, 0);
if (sockfd == -1)
{
perror (“socket”);
exit (EXIT_FAILURE);
}
使用函数socket创建套接字。
上述代码中,以下代码:
struct sockaddr_un addr;
addr.sun_family = AF_LOCAL;
strcpy (addr.sun_path, “mysock”);
准备地址结构,使用sockaddr_un结构体类型。
上述代码中,以下代码:
if (connect (sockfd, (struct sockaddr*)&addr, sizeof (addr)) == -1)
{
perror (“connect”);
exit (EXIT_FAILURE);
}
使用函数connect将套接字对象和对方的地址结构连接在一起。该函数有三个参数,说明如下:
第一个参数为套接字描述符
第二个参数为对方的地址结构
第三个参数为地址结构长度(以字节为单位)
上述代码中,以下代码:
char text[1024] = “你好,服务器”;
ssize_t written = write (sockfd, text, strlen(text));
if (written == -1)
{
perror (“write”);
exit (EXIT_FAILURE);
}
使用函数write通过套接字发送字节流。该函数有三个参数,说明如下:
第一个参数为套接字描述符
第二个参数为内存缓冲区
第三个参数为期望发送的字节数
上述代码中,以下代码:
if (close (sockfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
使用函数close关闭处于打开状态的套接字描述符,该函数的参数为处于打开状态的套接字描述符。
1.3 完整代码
本案例的完整代码如下所示:
服务器,代码如下所示:
#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int sockfd = socket (AF_LOCAL, SOCK_DGRAM, 0);
if (sockfd == -1)
{
perror (“socket”);
exit (EXIT_FAILURE);
}
struct sockaddr_un addr;
addr.sun_family = AF_LOCAL;
strcpy (addr.sun_path, “mysock”);
if (bind (sockfd, (struct sockaddr*)&addr, sizeof (addr)) == -1)
{
perror (“bind”);
unlink(“mysock”);
exit (EXIT_FAILURE);
}
char text[1024];
ssize_t readed = read (sockfd, text, 1024);
if (readed == -1)
{
perror (“read”);
unlink(“mysock”);
exit (EXIT_FAILURE);
}
printf(“客户机发送内容:%s\n”, text);
if (close (sockfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
unlink(“mysock”);
return 0;
}
客户端,代码如下所示:
#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int sockfd = socket (AF_LOCAL, SOCK_DGRAM, 0);
if (sockfd == -1)
{
perror (“socket”);
exit (EXIT_FAILURE);
}
struct sockaddr_un addr;
addr.sun_family = AF_LOCAL;
strcpy (addr.sun_path, “mysock”);
if (connect (sockfd, (struct sockaddr*)&addr, sizeof (addr)) == -1)
{
perror (“connect”);
exit (EXIT_FAILURE);
}
char text[1024] = “你好,服务器”;
ssize_t written = write (sockfd, text, strlen(text));
if (written == -1)
{
perror (“write”);
exit (EXIT_FAILURE);
}
if (close (sockfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
2 基于套接字的网络通信
2.1 问题
套接字(socket)是一个基于TCP/IP协议可实现基本网络通信功能的逻辑对象。机器与机器的通信,或者进程与进程的通信,在这里都可以被抽象地看作是套接字与套接字的通信。应用程序编写者无需了解网络协议的任何细节,更无需知晓系统内核和网络设备的运作机制,只要把想发送的数据写入套接字,或从套接字中读取想接收的数据即可。从这个意义上讲,套接字就相当于一个文件描述符,而网络就是一种特殊的文件,面向网络的编程与面向文件的编程已没有分别,而这恰恰是Unix系统一切皆文件思想的又一例证。
2.2 步骤
实现此案例需要按照如下步骤进行。
步骤一:服务器
代码如下所示:
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
int main()
{
int sockfd = socket (AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1)
{
perror (“socket”);
exit (EXIT_FAILURE);
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons (8888);
addr.sin_addr.s_addr = INADDR_ANY;
if (bind (sockfd, (struct sockaddr*)&addr, sizeof (addr)) == -1)
{
perror (“bind”);
exit (EXIT_FAILURE);
}
char text[1024];
ssize_t readed = read (sockfd, text, 1024);
if (readed == -1)
{
perror (“read”);
exit (EXIT_FAILURE);
}
printf(“客户机发送内容:%s\n”, text);
if (close (sockfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
上述代码中,以下代码:
int sockfd = socket (AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1)
{
perror (“socket”);
exit (EXIT_FAILURE);
}
使用函数socket创建套接字。
上述代码中,以下代码:
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons (8888);
addr.sin_addr.s_addr = INADDR_ANY;
准备地址结构,使用sockaddr_in结构体类型。
上述代码中,以下代码:
if (bind (sockfd, (struct sockaddr*)&addr, sizeof (addr)) == -1)
{
perror (“bind”);
exit (EXIT_FAILURE);
}
使用函数bind将套接字对象和自己的地址结构绑定在一起。
上述代码中,以下代码:
char text[1024];
ssize_t readed = read (sockfd, text, 1024);
if (readed == -1)
{
perror (“read”);
exit (EXIT_FAILURE);
}
printf(“客户机发送内容:%s\n”, text);
使用函数read通过套接字接收字节流。
上述代码中,以下代码:
if (close (sockfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
使用函数close关闭处于打开状态的套接字描述符,该函数的参数为处于打开状态的套接字描述符。
步骤二:客户端
代码如下所示:
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
int main()
{
int sockfd = socket (AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1)
{
perror (“socket”);
exit (EXIT_FAILURE);
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons (8888);
addr.sin_addr.s_addr = inet_addr(“127.0.0.1”);
if (connect (sockfd, (struct sockaddr*)&addr, sizeof (addr)) == -1)
{
perror (“connect”);
exit (EXIT_FAILURE);
}
char text[1024] = “你好,服务器”;
ssize_t written = write (sockfd, text, strlen(text));
if (written == -1)
{
perror (“write”);
exit (EXIT_FAILURE);
}
if (close (sockfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
上述代码中,以下代码:
int sockfd = socket (AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1)
{
perror (“socket”);
exit (EXIT_FAILURE);
}
使用函数socket创建套接字。
上述代码中,以下代码:
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons (8888);
addr.sin_addr.s_addr = inet_addr(“127.0.0.1”);
准备地址结构,使用sockaddr_in结构体类型。
上述代码中,以下代码:
if (connect (sockfd, (struct sockaddr*)&addr, sizeof (addr)) == -1)
{
perror (“connect”);
exit (EXIT_FAILURE);
}
使用函数connect将套接字对象和对方的地址结构连接在一起。
上述代码中,以下代码:
char text[1024] = “你好,服务器”;
ssize_t written = write (sockfd, text, strlen(text));
if (written == -1)
{
perror (“write”);
exit (EXIT_FAILURE);
}
使用函数write通过套接字发送字节流。
上述代码中,以下代码:
if (close (sockfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
使用函数close关闭处于打开状态的套接字描述符,该函数的参数为处于打开状态的套接字描述符。
2.3 完整代码
本案例的完整代码如下所示:
服务器,代码如下所示:
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
int main()
{
int sockfd = socket (AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1)
{
perror (“socket”);
exit (EXIT_FAILURE);
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons (8888);
addr.sin_addr.s_addr = INADDR_ANY;
if (bind (sockfd, (struct sockaddr*)&addr, sizeof (addr)) == -1)
{
perror (“bind”);
exit (EXIT_FAILURE);
}
char text[1024];
ssize_t readed = read (sockfd, text, 1024);
if (readed == -1)
{
perror (“read”);
exit (EXIT_FAILURE);
}
printf(“客户机发送内容:%s\n”, text);
if (close (sockfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
客户端,代码如下所示:
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
int main()
{
int sockfd = socket (AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1)
{
perror (“socket”);
exit (EXIT_FAILURE);
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons (8888);
addr.sin_addr.s_addr = inet_addr(“127.0.0.1”);
if (connect (sockfd, (struct sockaddr*)&addr, sizeof (addr)) == -1)
{
perror (“connect”);
exit (EXIT_FAILURE);
}
char text[1024] = “你好,服务器”;
ssize_t written = write (sockfd, text, strlen(text));
if (written == -1)
{
perror (“write”);
exit (EXIT_FAILURE);
}
if (close (sockfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
3 基于TCP协议的客户机与服务器
3.1 问题
一个完整TCP通信过程需要依次经历三个阶段:
首先,客户机必须建立与服务器的连接,所谓虚电路。
然后,凭借已建立好的连接,通信双方相互交换数据。
最后,客户机与服务器双双终止连接,结束通信过程。
3.2 步骤
实现此案例需要按照如下步骤进行。
步骤一:服务器
代码如下所示:
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
int main()
{
int listenfd = socket (AF_INET, SOCK_STREAM, 0);
if (listenfd == -1)
{
perror (“socket”);
exit (EXIT_FAILURE);
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons (8888);
addr.sin_addr.s_addr = INADDR_ANY;
if (bind (listenfd, (struct sockaddr*)&addr, sizeof (addr)) == -1)
{
perror (“bind”);
exit (EXIT_FAILURE);
}
if (listen (listenfd, 1024) == -1)
{
perror (“listen”);
exit (EXIT_FAILURE);
}
struct sockaddr_in addrcli = {};
socklen_t addrlen = sizeof (addrcli);
int connfd = accept (listenfd, (struct sockaddr*)&addrcli, &addrlen);
if (connfd == -1)
{
perror (“accept”);
exit (EXIT_FAILURE);
}
printf (“服务器已接受来自%s:%hu客户机的连接请求\n”, inet_ntoa (addrcli.sin_addr),ntohs (addrcli.sin_port));
char buf[1024];
ssize_t rcvd = recv (connfd, buf, sizeof (buf), 0);
if (rcvd == -1)
{
perror (“recv”);
exit (EXIT_FAILURE);
}
if (rcvd == 0)
{
printf (“客户机已关闭连接\n”);
exit (EXIT_FAILURE);
}
buf[rcvd] = ‘\0’;
printf (“客户端说:%s\n”, buf);
printf (“服务器说:”);
gets (buf);
ssize_t sent = send (connfd, buf, strlen (buf) * sizeof (buf[0]), 0);
if (sent == -1)
{
perror (“send”);
exit (EXIT_FAILURE);
}
if (close (listenfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
if (close (connfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
上述代码中,以下代码:
int listenfd = socket (AF_INET, SOCK_STREAM, 0);
if (listenfd == -1)
{
perror (“socket”);
exit (EXIT_FAILURE);
}
使用函数socket创建套接字。
上述代码中,以下代码:
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons (8888);
addr.sin_addr.s_addr = INADDR_ANY;
准备地址结构,使用sockaddr_in结构体类型。
上述代码中,以下代码:
if (bind (listenfd, (struct sockaddr*)&addr, sizeof (addr)) == -1)
{
perror (“bind”);
exit (EXIT_FAILURE);
}
使用函数bind将套接字对象和自己的地址结构绑定在一起。
上述代码中,以下代码:
if (listen (listenfd, 1024) == -1)
{
perror (“listen”);
exit (EXIT_FAILURE);
}
使用函数listen在指定套接字上启动对连接请求的侦听。该函数有两个参数,说明如下:
第一个参数为套接字描述符。
第二个参数为连接请求的最大值。
上述代码中,以下代码:
struct sockaddr_in addrcli = {};
socklen_t addrlen = sizeof (addrcli);
int connfd = accept (listenfd, (struct sockaddr*)&addrcli, &addrlen);
if (connfd == -1)
{
perror (“accept”);
exit (EXIT_FAILURE);
}
printf (“服务器已接受来自%s:%hu客户机的连接请求\n”, inet_ntoa (addrcli.sin_addr),ntohs (addrcli.sin_port));
使用函数accept在指定套接字上等待并接受连接请求。该函数有三个参数,说明如下:
第一个参数为套接字描述符。
第二个参数为输出连接请求发起者地址结构。
第三个参数为输入/输出,连接请求发起者地址结构长度(以字节为单位)。
上述代码中,以下代码:
char buf[1024];
ssize_t rcvd = recv (connfd, buf, sizeof (buf), 0);
if (rcvd == -1)
{
perror (“recv”);
exit (EXIT_FAILURE);
}
if (rcvd == 0)
{
printf (“客户机已关闭连接\n”);
exit (EXIT_FAILURE);
}
buf[rcvd] = ‘\0’;
printf (“客户端说:%s\n”, buf);
使用函数recv通过指定套接字接收数据,该函数有四个参数,说明如下:
第一个参数为套接字描述符。
第二个参数为应用程序接收缓冲区。
第三个参数为期望接收的字节数。
第四个参数为接收标志,一般取0,还可取以下值:
MSG_DONTWAIT - 以非阻塞方式接受数据。
MSG_OOB - 接收带外数据。
MSG_PEEK - 只查看可接收的数据,函数返回后数据依然留在接收缓冲区中。
MSG_WAITALL - 等待所有数据,即不接收到len字节的数据,函数就不返回。
上述代码中,以下代码:
printf ("服务器说:");
gets (buf);
ssize_t sent = send (connfd, buf, strlen (buf) * sizeof (buf[0]), 0);
if (sent == -1)
{
perror (“send”);
exit (EXIT_FAILURE);
}
使用函数send通过指定套接字发送数据,该函数有四个参数,说明如下:
第一个参数为套接字描述符。
第二个参数为应用程序发送缓冲区。
第三个参数为期望发送的字节数。
第四个参数为接收标志,一般取0,还可取以下值:
MSG_DONTWAIT - 以非阻塞方式发送数据。
MSG_OOB - 发送带外数据。
MSG_DONTROUTE - 不查路由表,直接在本地网络中寻找目的主机
上述代码中,以下代码:
if (close (listenfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
if (close (connfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
使用函数close关闭处于打开状态的套接字描述符,该函数的参数为处于打开状态的套接字描述符。
步骤二:客户端
代码如下所示:
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
int main()
{
int listenfd = socket (AF_INET, SOCK_STREAM, 0);
if (listenfd == -1)
{
perror (“socket”);
exit (EXIT_FAILURE);
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons (8888);
addr.sin_addr.s_addr = inet_addr(“127.0.0.1”);
if (connect (listenfd, (struct sockaddr*)&addr, sizeof (addr)) == -1)
{
perror (“connect”);
exit (EXIT_FAILURE);
}
char buf[1024] = “你好,服务器”;
printf (“客户端说:%s\n”, buf);
ssize_t sent = send (listenfd, buf, strlen (buf) * sizeof (buf[0]), 0);
if (sent == -1)
{
perror (“send”);
exit (EXIT_FAILURE);
}
ssize_t rcvd = recv (listenfd, buf, sizeof (buf), 0);
if (rcvd == -1)
{
perror (“recv”);
exit (EXIT_FAILURE);
}
buf[rcvd] = ‘\0’;
printf (“服务器说:%s\n”, buf);
if (close (listenfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
上述代码中,以下代码:
int listenfd = socket (AF_INET, SOCK_STREAM, 0);
if (listenfd == -1)
{
perror (“socket”);
exit (EXIT_FAILURE);
}
使用函数socket创建套接字。
上述代码中,以下代码:
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons (8888);
addr.sin_addr.s_addr = inet_addr(“127.0.0.1”);
准备地址结构,使用sockaddr_in结构体类型。
上述代码中,以下代码:
if (connect (listenfd, (struct sockaddr*)&addr, sizeof (addr)) == -1)
{
perror (“connect”);
exit (EXIT_FAILURE);
}
使用函数connect将套接字对象和对方的地址结构连接在一起。
上述代码中,以下代码:
char buf[1024] = “你好,服务器”;
printf (“客户端说:%s\n”, buf);
ssize_t sent = send (listenfd, buf, strlen (buf) * sizeof (buf[0]), 0);
if (sent == -1)
{
perror (“send”);
exit (EXIT_FAILURE);
}
使用函数send通过指定套接字发送数据。
上述代码中,以下代码:
ssize_t rcvd = recv (listenfd, buf, sizeof (buf), 0);
if (rcvd == -1)
{
perror (“recv”);
exit (EXIT_FAILURE);
}
buf[rcvd] = ‘\0’;
printf (“服务器说:%s\n”, buf);
使用函数recv通过指定套接字接收数据。
上述代码中,以下代码:
if (close (listenfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
使用函数close关闭处于打开状态的套接字描述符,该函数的参数为处于打开状态的套接字描述符。
3.3 完整代码
本案例的完整代码如下所示:
服务器,代码如下所示:
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
int main()
{
int listenfd = socket (AF_INET, SOCK_STREAM, 0);
if (listenfd == -1)
{
perror (“socket”);
exit (EXIT_FAILURE);
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons (8888);
addr.sin_addr.s_addr = INADDR_ANY;
if (bind (listenfd, (struct sockaddr*)&addr, sizeof (addr)) == -1)
{
perror (“bind”);
exit (EXIT_FAILURE);
}
if (listen (listenfd, 1024) == -1)
{
perror (“listen”);
exit (EXIT_FAILURE);
}
struct sockaddr_in addrcli = {};
socklen_t addrlen = sizeof (addrcli);
int connfd = accept (listenfd, (struct sockaddr*)&addrcli, &addrlen);
if (connfd == -1)
{
perror (“accept”);
exit (EXIT_FAILURE);
}
printf (“服务器已接受来自%s:%hu客户机的连接请求\n”, inet_ntoa (addrcli.sin_addr),ntohs (addrcli.sin_port));
char buf[1024];
ssize_t rcvd = recv (connfd, buf, sizeof (buf), 0);
if (rcvd == -1)
{
perror (“recv”);
exit (EXIT_FAILURE);
}
if (rcvd == 0)
{
printf (“客户机已关闭连接\n”);
exit (EXIT_FAILURE);
}
buf[rcvd] = ‘\0’;
printf (“客户端说:%s\n”, buf);
printf (“服务器说:”);
gets (buf);
ssize_t sent = send (connfd, buf, strlen (buf) * sizeof (buf[0]), 0);
if (sent == -1)
{
perror (“send”);
exit (EXIT_FAILURE);
}
if (close (listenfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
if (close (connfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
客户端,代码如下所示:
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
int main()
{
int listenfd = socket (AF_INET, SOCK_STREAM, 0);
if (listenfd == -1)
{
perror (“socket”);
exit (EXIT_FAILURE);
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons (8888);
addr.sin_addr.s_addr = inet_addr(“127.0.0.1”);
if (connect (listenfd, (struct sockaddr*)&addr, sizeof (addr)) == -1)
{
perror (“connect”);
exit (EXIT_FAILURE);
}
char buf[1024] = “你好,服务器”;
printf (“客户端说:%s\n”, buf);
ssize_t sent = send (listenfd, buf, strlen (buf) * sizeof (buf[0]), 0);
if (sent == -1)
{
perror (“send”);
exit (EXIT_FAILURE);
}
ssize_t rcvd = recv (listenfd, buf, sizeof (buf), 0);
if (rcvd == -1)
{
perror (“recv”);
exit (EXIT_FAILURE);
}
buf[rcvd] = ‘\0’;
printf (“服务器说:%s\n”, buf);
if (close (listenfd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}