计算机网络实验七 Socket Programming


Objective

To get the details of socket programming and simple client-server interaction. It is covered in §6.1 of your text. Review that section before doing this lab.

Requirements

You are going to build a server capable of receiving text messages from clients. The server should print these text messages on standard output, but should not print any other messages such as debug information. From the server perspective, a message corresponds to the data received from a particular client during a communication session with that client. The server should be listening for text messages to a port known to the clients. The server should be able to receive text messages from multiple clients. When multiple clients simultaneously try to send text messages to the server, the server should print them one at a time (in any order). Note that you don't have to implement an event-driven or multi-threaded server. Serving one client at a time is enough.

构建一个能够从客户端接收文本消息的服务器。
服务器在标准输出上打印这些文本消息,但不应打印任何其他消息,如调试信息。
从服务器的角度来看,消息对应于与特定客户端的通信期间从这个客户端接收的数据。
服务器应侦听客户端已知端口的文本消息。
服务器应该能够接收来自多个客户端的文本消息。当多个客户端同时尝试向服务器发送文本消息时,服务器应一次打印一条(按任意顺序。
注意,不必实现事件驱动或多线程服务器。一次为一个客户提供服务就足够了。

You should also implement a client to test the server. The client should receive the text message from standard input. The end of the message is marked by a control sequence which corresponds to hitting >ENTER< twice. This control sequence is also an instruction for the client to exit. This control sequence should not be transmitted. Also, if your client reads the text message from a file via pipes, and reaches EOF without seeing the control sequence, then the client should still transmit the message and exit.

还应实现客户端client 来测试服务器。
客户端从标准输入接收文本消息。
        消息结束的标记 a control sequence,对应于按 >ENTER< 两次。也是客户端退出的指令。
        不需要传输这个 control sequence。
同时,如果客户端通过管道从file文档中读取文本消息,并在没有看到 control sequence的情况下到达 EOF,则客户端应传输消息并退出。

This assignment can be completed in your favorite programming language. It should compile and run without errors by producing two binaries called server and client. The server should take as its first argument the port to listen to. The client should take as its first argument the name of the host that the server is running and the port that the server is listening. If the server cannot bind to the port that you specify, a message should be printed on standard error and the program should exit. You shouldn't assume that your server will be running on a particular IP address, or that clients will be coming from a predetermined IP address. Both the client and server should generate an appropriate error message and terminate when given invalid arguments.

可用喜欢的编程语言完成。应该能通过两个二进制文件(server and client)来编译运行。
server 服务器:参数1:正在监听的端口
client 客户端:参数1:服务器正在运行的主机名称、服务器正在监听的端口
如果服务器无法绑定到指定的端口,在标准错误时print消息、退出程序。
不能假设服务器在特定IP地址上运行or客户端来自预定的IP
客户端、服务器都应该能生成恰当的错误信息,在遇到非法参数时终止。

You should test your code with long text messages (of size at least 20KB), not just short ones. You can use pipes to redirect the standard input of the client and standard output of the server. You should also test your code with multiple clients. (at least up to 5 simultaneous clients)

利用长文本信息(≥20KB)测试代码。
可以利用管道重定向客户端标准输入和服务器的标准输出。
使用多可客户端测试代码(至少最多5个并发客户端)

The deliverables are two files: "server.c" and "client.c" implementing the server and client as described above and an optional makefile for producing the executables.

两个文件 "server.c" and "client.c"

NOTE: if your implementation of client and server is capable of duplex communication, you can get 5 extra points added to your final grade. 

双工通信++;

Example Implementation: simplex-talk

Here is an example implementation of a simple client/server program that uses the socket interface to send messages over a TCP connection. This application allows a user on one machine to type in and send text to a user on another machine. It is a simplified version of the Unix talk program, which is similar to the program at the core of an instant messaging application.

下面是一个简单的客户端/服务器进程的示例实现,程序使用socket接口通过 TCP 连接发送消息。此应用进程允许一台计算机上的用户输入文本发送给另一台计算机上的用户。
是Unix谈话进程的简化版本,类似于即时消息应用进程核心的进程。

Client

The client side takes the name of the remote machine as an argument. It calls the Unix utility gethostbyname to translate this name into the remote host’s IP address. The next step is to construct the address data structure (sin) expected by the socket interface. Notice that this data structure specifies that we’ll be using the socket to connect to the Internet (AF_INET). Here we use TCP port 7701 as the server port. The final step in setting up the connection is to call socket and connect. Once the connect operation returns, the connection is established and the client program enters its main loop, which reads text from standard input and sends it over the socket.

客户端将远程计算机的名称作为参数。
调用 Unix 实用进程 gethostbyname 将此名称转换为远程主机的 IP 地址。
下一步是构造套接字接口预期的地址数据结构 (sin)。
注意:此数据结构指定我们将使用套接字连接到互联网 (AF_INET)。
这里我们使用TCP端口7701作为服务器端口。设置连接的最后一步是调用套接字并连接。连接操作返回后,连接创建,客户端进程进入其主循环,该循环从标准输入读取文本并通过套接字发送。

/* Source: Peterson & Davie (2007), Computer Networks, a Systems Approach,
 *           4th ed., Morgan Kaufmann, p. 34-35.
 * Included stdlib.h, string.h, and strings.h so it compiles on Linux.
 * Changed port from 5432 (postgresql) to 7701 (unassigned).
 * - JLND Feb 7 2009
 */
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
/*添加头文件*/
#include <unistd.h>

#define SERVER_PORT 7701
#define MAX_LINE 256

int main(int argc, char * argv[])
{
  FILE *fp;
  struct hostent *hp;
  struct sockaddr_in sin;
  char *host;
  char buf[MAX_LINE];
  int s;
  int len;

  if (argc==2) {
    host = argv[1];
  }
  else {
    fprintf(stderr, "usage: simplex-talk host\n");
    exit(1);
  }

  /* translate host name into peer’s IP address */
  hp = gethostbyname(host);
  if (!hp) {
    fprintf(stderr, "simplex-talk: unknown host: %s\n", host);
    exit(1);
  }

  /* build address data structure */
  bzero((char *)&sin, sizeof(sin));
  sin.sin_family = AF_INET;
  bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
  sin.sin_port = htons(SERVER_PORT);

  /* active open */
  if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
    perror("simplex-talk: socket");
    exit(1);
  }
  if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
    perror("simplex-talk: connect");
    close(s);
    exit(1);
  }

  /* main loop: get and send lines of text */
  while (fgets(buf, sizeof(buf), stdin)) {
    buf[MAX_LINE-1] = '\0';
    len = strlen(buf) + 1;
    send(s, buf, len, 0);
  }
}

Server

The server first constructs the address data structure by filling in its own port number (SERVER_PORT). By not specifying an IP address, the application program is willing to accept connections on any of the local host’s IP addresses. Next, the server performs the preliminary steps involved in a passive open; it creates the socket, binds it to the local address, and sets the maximum number of pending connections to be allowed. Finally, the main loop waits for a remote host to try to connect, and when one does, it receives and prints out the characters that arrive on the connection.

服务器首先通过填写自己的端口号 (SERVER_PORT) 来构造地址数据结构。
不指定 IP 地址,应用进程愿意接受任何本地主机 IP 地址上的连接。
接下来,服务器执行被动打开中涉及的预备步骤;它创建套接字,将其绑定到本地地址,并设置允许的最大挂起连接数。
最后,主循环等待远程主机尝试连接,当远程主机尝试连接时,它会接收并打印出到达连接的字符。
 

/* Source: Peterson & Davie (2007), Computer Networks, a Systems Approach,
 *           4th ed., Morgan Kaufmann, p. 35-36.
 * Included stdlib.h, string.h, and strings.h so it compiles on Linux.
 * Changed port from 5432 (postgresql) to 7701 (unassigned).
 * - JLND Feb 7 2009
 */

#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
/*添加头文件*/
#include <unistd.h>

#define SERVER_PORT 7701
#define MAX_PENDING 5
#define MAX_LINE 256

int
main()
{
  struct sockaddr_in sin;
  char buf[MAX_LINE];
  int len;
  int s, new_s;

  /* build address data structure */
  bzero((char *)&sin, sizeof(sin));
  sin.sin_family = AF_INET;
  sin.sin_addr.s_addr = INADDR_ANY;
  sin.sin_port = htons(SERVER_PORT);
 
  /* setup passive open */
  if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
    perror("simplex-talk: socket");
    exit(1);
  }
  if ((bind(s, (struct sockaddr *)&sin, sizeof(sin))) < 0) {
    perror("simplex-talk: bind");
    exit(1);
  }
  listen(s, MAX_PENDING);
 
  /* wait for connection, then receive and print text */
  while(1) {
    if ((new_s = accept(s, (struct sockaddr *)&sin, &len)) < 0) {
      perror("simplex-talk: accept");
      exit(1);
    }
    while (len = recv(new_s, buf, sizeof(buf), 0))
      fputs(buf, stdout);	
    close(new_s);
  }
}

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值