丨budboool · 12月10日 · 广东

百问FB网络编程 - TCP/UDP编程简单示例

6.4 TCP编程简单示例

​ 服务器首先进行初始化操作:调用函数socket创建一个套接字,函数bind将这个套接字与服务器的公认地址绑定在一起,函数listen将这个套接字换成倾听套接字,然后调用函数accept来等待客户机的请求。过了一段时间后,客户机启动,调用socket创建一个套接字,然后调用函数connect来与服务器建立连接。连接建立之后,客户机和服务器通过读、写套接字来进行通信。

6.4.1 服务器端代码

参考:TCP/server_line.c

1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <sys/types.h>
5#include <sys/socket.h>
6#include <netinet/in.h>
7#include <arpa/inet.h>
8#include <unistd.h>
9#include <signal.h>
10
11#define SERVER_PORT 8180
12#define C_QUEUE     10 
13
14/************************************************************
15*函数功能描述:从8180端口接收客户端数据
16*输入参数:无
17*输出参数:打印客户IP以及发来的信息
18*返回值:无
19*修改日期        版本号        修改人        修改内容
20*2020/05/13        v1.0.0        zonghzha    reat
21*************************************************************/
22
23int main(int argc, char **argv)
24{
25    char buf[512];
26    int len;
27    int duty_socket;
28    int customer_socket;
29    struct sockaddr_in socket_server_addr;
30    struct sockaddr_in socket_client_addr;
31    int ret;
32    int addr_len;
33
34    signal(SIGCHLD, SIG_IGN);
35    
36      /* 服务器端开始建立socket描述符 */
37    duty_socket = socket(AF_INET, SOCK_STREAM, 0);
38    if (duty_socket == -1)
39    {
40        printf("socket error");
41        return -1;
42    }
43    
44      /* 服务器端填充 sockaddr_in结构 */
45    socket_server_addr.sin_family   = AF_INET;
46      /* 端口号转换为网络字节序 */
47    socket_server_addr.sin_port     = htons(SERVER_PORT);
48      /* 接收本机所有网口的数据 */
49    socket_server_addr.sin_addr.s_addr  = INADDR_ANY;
50    memset(socket_server_addr.sin_zero, 0, 8);
51    
52      /* 捆绑sockfd描述符 */
53    ret = bind(duty_socket, (const struct sockaddr *)&socket_server_addr, sizeof(struct sockaddr));
54    if (ret == -1)
55    {
56        printf("bind error!\n");
57        return -1;
58    }
59    ret = listen(duty_socket, C_QUEUE);
60    if (ret == -1)
61    {
62        printf("listen error!\n");
63        return -1;
64    }
65    
66    while (1)
67    {
68        addr_len = sizeof(struct sockaddr);
69          /* 服务器阻塞,直到客户程序建立连接 */
70        customer_socket = accept(duty_socket, (struct sockaddr *)&socket_client_addr, &addr_len);
71        if (customer_socket != -1)
72        {
73              /*inet_ntoa的作用是将一个32位Ipv4地址转换为相应的点分十进制数串*/
74            printf("Get connect from %s\n", inet_ntoa(socket_client_addr.sin_addr));
75        }
76        if (!fork())
77        {
78            while (1)
79            {
80                memset(buf, 512, 0);
81                  /*接收数据*/
82                len = recv(customer_socket, buf, sizeof(buf), 0);
83                buf[len] = '\0';
84                if (len <= 0)
85                {
86                    close(customer_socket);
87                    return -1;
88                }
89                else
90                {
91                    printf("Get connect from %s, Msg is %s\n", inet_ntoa(socket_client_addr.sin_addr), buf);
92                }
93            }
94        }
95    }
96    
97    close(duty_socket);
98    return 0;
99}

6.4.2 客户端代码

参考:TCP/client_line.c

1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <sys/types.h>
5#include <sys/socket.h>
6#include <netinet/in.h>
7#include <arpa/inet.h>
8#include <unistd.h>
9
10#define SERVER_PORT 8180
11/************************************************************
12*函数功能描述:向指定IP的8180端口发送数据
13*输入参数:点分十进制服务器IP
14*输出参数:无
15*返回值:无
16*修改日期        版本号        修改人        修改内容
17*2020/05/13        v1.0.0        zonghzha    creat
18*************************************************************/
19
20int main(int argc, char **argv)
21{
22    unsigned char buf[512];
23    int len;
24    struct sockaddr_in socket_server_addr;
25    int ret;
26    int addr_len;
27    int client_socket;
28
29    
30    if (argc != 2)
31    {
32        printf("Usage:\n");
33        printf("%s <server_ip>\n", argv[0]);
34        return -1;
35    }
36    
37    /* 客户程序开始建立 sockfd描述符 */
38    client_socket = socket(AF_INET, SOCK_STREAM, 0);
39    if (client_socket == -1)
40    {
41        printf("socket error");
42        return -1;
43    }
44    
45      /* 客户程序填充服务端的资料 */
46    socket_server_addr.sin_family   = AF_INET;
47      /*主机字节序转换为网络字节序*/
48    socket_server_addr.sin_port     = htons(SERVER_PORT);
49    if (inet_aton(argv[1], &socket_server_addr.sin_addr) == 0)
50    {
51        printf("invalid server ip\n");
52        return -1;
53    }
54    memset(socket_server_addr.sin_zero, 0, 8);
55    /* 客户程序发起连接请求 */
56    ret = connect(client_socket, (const struct sockaddr *)&socket_server_addr, sizeof(struct sockaddr));
57    if (ret == -1)
58    {
59        printf("connect error!\n");
60        return -1;
61    }
62
63    
64    while (1)
65    {
66        if (fgets(buf, sizeof(buf), stdin))
67        {
68            len = send(client_socket, buf, strlen(buf), 0);
69            if (len <= 0)
70            {
71                close(client_socket);
72                return -1;
73            }
74        }
75    }
76    
77    close(client_socket);
78    return 0;
79}

6.4.3 Makefile文件

all:server client
server:server.c
    gcc $^ -o $@
client:client.c
    gcc $^ -o $@
clean:
    rm server client -f

(注意:命令语句的开头要用“Tab”键。)

6.4.4 执行

服务器端:

./server

客户端:

./client 127.0.0.1

6.5 UDP编程简单示例

​ UDP服务器首先进行初始化操作:调用函数socket创建一个数据报类型的套接字,函数bind将这个套接字与服务器的公认地址绑定在一起。然后调用函数recvfrom接收UDP客户机的数据报。UDP客户机首先调用函数socket创建一个数据报套接字,然后调用函数sendto向服务器发送数据报。在结束通信后,客户机调用close关闭UDP套接字,服务器继续使用这个UDP套接字接收其它客户机的数据报。

6.5.1 服务器端代码

参考UDP/server_line.c

1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4//#include <sys/type.h>
5#include <sys/socket.h>
6#include <netinet/in.h>
7#include <arpa/inet.h>
8#include <unistd.h>
9#include <signal.h>
10
11/*服务器端口为8180*/
12#define SERVER_PORT 8180
13
14/************************************************************
15*函数功能描述:从8180端口接收客户端数据
16*输入参数:无
17*输出参数:打印客户IP以及发来的信息
18*返回值:无
19*修改日期            版本号            修改人            修改内容
20*2020/05/13            v1.0.0            zonghzha        creat
21*************************************************************/
22
23
24int main(int argc, char **argv)
25{
26    unsigned char buf[512];
27    int len;
28    int duty_socket;
29    int customer_socket;
30    struct sockaddr_in socket_server_addr;
31    struct sockaddr_in socket_client_addr;
32    int ret;
33    int addr_len;
34
35      /* 创建数据报套接字 */
36    duty_socket = socket(AF_INET, SOCK_DGRAM, 0);
37    if (duty_socket == -1)
38    {
39        printf("socket error");
40        return -1;
41    }
42    
43      /* 服务器端填充 sockaddr_in结构 */
44    socket_server_addr.sin_family   = AF_INET;
45    socket_server_addr.sin_port     = htons(SERVER_PORT);
46    socket_server_addr.sin_addr.s_addr  = INADDR_ANY;
47    memset(socket_server_addr.sin_zero, 0, 8);
48    
49      /*绑定套接字*/
50    ret = bind(duty_socket, (const struct sockaddr *)&socket_server_addr, sizeof(struct sockaddr));
51    if (ret == -1)
52    {
53        printf("bind error!\n");
54        return -1;
55    }
56
57    
58    while (1)
59    {
60        addr_len = sizeof(struct sockaddr);
61          /* 接收客户端数据报,返回的为接收到的字节数 */ 
62        len = recvfrom(duty_socket, buf, sizeof(buf), 0, (struct sockaddr *)&socket_client_addr, &addr_len);
63        if (len > 0)
64        {
65            buf[len] = '\0';
66            printf("Get Msg from %s : %s\n", inet_ntoa(socket_client_addr.sin_addr), buf);
67        }
68   
69    }
70    
71    close(duty_socket);
72    return 0;
73}
74

6.5.2 客户端代码

6.5.2.1 客户端程序1

参考UDP/client_line_1.c

1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <sys/socket.h>
5#include <netinet/in.h>
6#include <arpa/inet.h>
7#include <unistd.h>
8
9#define SERVER_PORT 8180
10
11/************************************************************
12*函数功能描述:向指定IP的8180端口发送数据
13*输入参数:点分十进制服务器IP
14*输出参数:无
15*返回值:无
16*修改日期            版本号            修改人            修改内容
17*2020/05/13            v1.0.0            zonghzha        creat
18*************************************************************/
19
20int main(int argc, char **argv)
21{
22    unsigned char buf[512];
23    int len;
24    struct sockaddr_in socket_server_addr;
25    int ret;
26    int addr_len;
27    int client_socket;
28
29    
30    if (argc != 2)
31    {
32        printf("Usage:\n");
33        printf("%s <server_ip>\n", argv[0]);
34        return -1;
35    }
36    
37    /*创建套接字*/
38    client_socket = socket(AF_INET, SOCK_DGRAM, 0);
39    if (client_socket == -1)
40    {
41        printf("socket error");
42        return -1;
43    }
44    
45      /* 填充服务端的资料 */
46    socket_server_addr.sin_family   = AF_INET;
47    socket_server_addr.sin_port     = htons(SERVER_PORT);
48    if (inet_aton(argv[1], &socket_server_addr.sin_addr) == 0)
49    {
50        printf("invalid server ip\n");
51        return -1;
52    }
53    memset(socket_server_addr.sin_zero, 0, 8);
54    
55
56
57    
58    while (1)
59    {
60        if (fgets(buf, sizeof(buf), stdin))
61        {
62 //           len = send(client_socket, buf, strlen(buf), 0);
63              /*向服务器端发送数据报*/
64            addr_len = sizeof(struct sockaddr);
65            len = sendto(client_socket, buf, sizeof(buf), 0, (struct sockaddr *)&socket_server_addr, addr_len);
66            if (len <= 0)
67            {
68                close(client_socket);
69                return -1;
70            }
71        }
72    }
73    
74    close(client_socket);
75    return 0;
76}
77

问:用UDP协议写网络通讯程序不可以用connect函数吗?

答:非也。

6.5.2.2 客户端程序2

参考UDP/client_line_2.c

1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <sys/socket.h>
5#include <netinet/in.h>
6#include <arpa/inet.h>
7#include <unistd.h>
8
9/*服务器端口为8180*/
10#define SERVER_PORT 8180
11
12/************************************************************
13*函数功能描述:向指定IP的8180端口发送数据
14*输入参数:点分十进制服务器IP
15*输出参数:无
16*返回值:无
17*修改日期            版本号            修改人            修改内容
18*2020/05/13            v1.0.0            zonghzha        creat
19*************************************************************/
20
21int main(int argc, char **argv)
22{
23    unsigned char buf[512];
24    int len;
25    struct sockaddr_in socket_server_addr;
26    int ret;
27    int addr_len;
28    int client_socket;
29
30    
31    if (argc != 2)
32    {
33        printf("Usage:\n");
34        printf("%s <server_ip>\n", argv[0]);
35        return -1;
36    }
37    
38    /*创建数据报套接字*/
39    client_socket = socket(AF_INET, SOCK_DGRAM, 0);
40    if (client_socket == -1)
41    {
42        printf("socket error");
43        return -1;
44    }
45    
46    socket_server_addr.sin_family   = AF_INET;
47    socket_server_addr.sin_port     = htons(SERVER_PORT);
48    if (inet_aton(argv[1], &socket_server_addr.sin_addr) == 0)
49    {
50        printf("invalid server ip\n");
51        return -1;
52    }
53    memset(socket_server_addr.sin_zero, 0, 8);
54    
55    ret = connect(client_socket, (const struct sockaddr *)&socket_server_addr, sizeof(struct sockaddr));
56    if (ret == -1)
57    {
58        printf("connect error!\n");
59        return -1;
60    }
61
62    
63    while (1)
64    {
65        if (fgets(buf, sizeof(buf), stdin))
66        {
67            len = send(client_socket, buf, strlen(buf), 0);
68            if (len <= 0)
69            {
70                close(client_socket);
71                return -1;
72            }
73        }
74    }
75    
76    close(client_socket);
77    return 0;
78}
79

​ 在客户端代码2中,connect函数并非真的在协议层建立了连接,它只是指定了服务器的地址和端口号信息。

​ 因为在connect中指定了服务器的地址和端口号信息,所以后面的send就可以直接发送了,而不用再次指定地址和端口号。

6.5.3 Makefile文件

all:server client_1 client_2
server:server.c
    gcc $^ -o $@
client_1:client_1.c
    gcc $^ -o $@
client_2:client_2.c
    gcc $^ -o $@
clean:
    rm server client_1 client_2 -f

(注意:命令语句的开头要用“Tab”键。)

6.5.4 执行

服务器端执行:

./server

客户端执行:

./client_1 127.0.0.1

客户端输入:

good night

服务器端显示:

Get Msg from 127.0.0.1 : good night

客户端输入:

good night

服务器端显示:

Get connect from 127.0.0.1
Get connect from 127.0.0.1, Msg is good night
推荐阅读
关注数
19
文章数
104
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息