C/S模型-TCP
在创建socket时,若将socket()函数中的参数type设置为SOCK_STREAM,程序将采用TCP传输协议,先使通信双方建立连接,再以数据段的形式传输数据。
案例1:编写C/S模式的程序,分别创建服务器和客户端。客户端的功能是从终端获取一个字符串发送给服务器,然后接收服务器返回的字符串并打印;服务器的功能是从客户端发来的字符,将每个字符转换为大写再返回给客户端。案例实现如下。
tcpserver.c //服务器端程序
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <sys/socket.h>
6 #include <netinet/in.h>
7 #include <arpa/inet.h>
8 #define MAXLINE 80 //最大连接数
9 #define SERV_PORT 6666 //服务器端口号
10 int main(void)
11 {
12 struct sockaddr_in servaddr, cliaddr; //定义服务器与客户端地址结构体
13 socklen_t cliaddr_len; //客户端地址长度
14 int listenfd, connfd;
15 char buf[MAXLINE];
16 char str[INET_ADDRSTRLEN];
17 int i, n;
18 //创建服务器端套接字文件
19 listenfd = socket(AF_INET, SOCK_STREAM, 0);
20 //初始化服务器端口地址
21 bzero(&servaddr, sizeof(servaddr)); //将服务器端口地址清零
22 servaddr.sin_family = AF_INET;
23 servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
24 servaddr.sin_port = htons(SERV_PORT);
25 //将套接字文件与服务器端口地址绑定
26 bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
27 //监听,并设置最大连接数未20
28 listen(listenfd, 20);
29 printf("Accepting connections ...\n");
30 //接收客户端数据,并处理请求
31 while (1) {
32 cliaddr_len = sizeof(cliaddr);
33 connfd =accept(listenfd, (struct sockaddr *)&cliaddr,&cliaddr_len);
34 n = recv(connfd, buf, MAXLINE,0);
35 printf("received from %s at PORT %d\n",
36 inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
37 ntohs(cliaddr.sin_port));
38 for (i = 0; i < n; i++)
39 buf[i] = toupper(buf[i]);
40 send(connfd, buf, n,0);
41 //关闭连接
42 close(connfd);
43 }
44 return 0;
45 }
tcpclient.c 客户端程序
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <sys/socket.h>
6 #include <netinet/in.h>
7 #define MAXLINE 80
8 #define SERV_PORT 6666
9 int main(int argc, char *argv[])
10 {
11 struct sockaddr_in servaddr; //定义服务器地址结构体
12 char buf[MAXLINE];
13 int sockfd, n;
14 char *str;
15 if (argc != 2) {
16 fputs("usage: ./client message\n", stderr);
17 exit(1);
18 }
19 str = argv[1];
20 //创建客户端套接字文件
21 sockfd = socket(AF_INET, SOCK_STREAM, 0);
22 //初始化服务器端口地址
23 bzero(&servaddr, sizeof(servaddr));
24 servaddr.sin_family = AF_INET;
25 inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
26 servaddr.sin_port = htons(SERV_PORT);
27 //请求链接
28 connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
29 //发送数据
30 send(sockfd, str, strlen(str),0);
31 //接收客户端返回的数据
32 n = recv(sockfd, buf, MAXLINE,0);
33 printf("Response from server:\n");
34 //将客户端返回的数据打印到终端
35 write(STDOUT_FILENO, buf, n);
36 //关闭连接
37 close(sockfd);
38 return 0;
39 }
编译以上两端代码,打开两个终端窗口,先执行服务器端程序,再执行客户端程序,同时输入需要转换的字符串,服务器端和客户端对应的终端中分别打印如下信息:
服务器端:
Accepting connections ...
received from 127.0.0.1 at PORT 41957
received from 127.0.0.1 at PORT 41958
客户机端:
[itheima@localhost ~]$ ./tcpclient hello
Response from server:
HELLO[itheima@localhost ~]$ ./tcpclient helloworld
Response from server:
HELLOWORLD[itheima@localhost ~]$
由程序执行结果可知,服务器成功将客户端发来的字符串转换成大写,案例实现成功。