网络编程之套接字(tcp)

  经过几天高强度的学习,对套接字的编程有了初步的认识,今天对这几天所学的知识总结一下;首先简单阐述一下tcp通信;

  TCP提供的是可靠的,顺序的,以及不会重复的数据传输,处理流控制,由于TCP是可靠的,连接的,顺序的,所以TCP一般用于都应用于对传输的完整性,正确性要求严的场合;编写基于tcp的服务器-客户端模型的程序简单流程如下:

  服务器端:

  (1)调用socket()创建一个套接口

  (2)调用bind()函数是服务器进程与一个端口绑定

  (3)调用listen()设置客户接入队列的大小

  (4)调用accept()接受一个连接,如果介入的队列不为空,则返回一个已连接的套接口描述符,

  (5)调用sned()和recv()函数用来在已连接的套接口间进行发送和接收数据

  客户端:

  (1)调用socket()创建套接字

  (2)调用connect()函数向服务器发送连接请求;

  (3)调用send()函数和recv()函数

  下面是服务器端的代码;

 1 #include <stdio.h>
 2 #include <sys/socket.h>
 3 #include <netinet/in.h>
 4
 5 //server
 6 int main()
 7 {
 8     int fd = 0;
 9     int nfd = 0;
10     int ret = 0;
11     unsigned char data[1024] = {0};
12
13     fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
14     if(fd < 0) {
15         perror("socket");
16         return 1;
17     }
18     /*服务端信息*/
19     struct sockaddr_in ser;
20     ser.sin_family = AF_INET;
21     ser.sin_port = htons(2009);
22     ser.sin_addr.s_addr = htonl(0xc0a8010a);//192.168.1.10
23     struct sockaddr_in clt;
24     int len = 0;
25
26     /*绑定*/
27     ret = bind(fd, (struct sockaddr *)&ser, 16);
28     if(ret < 0) {
29         perror("bind");
30         return 1;
31     }
32
33     /*监听*/
34     ret = listen(fd, 10);
35     if(ret == -1) {
36         perror("listen");
37         return 1;
38     }
39
40     /*接收连接,并且返回一个新的套接字描述符nfd*/
41     nfd = accept(fd, (struct sockaddr *)&clt, &len);
42     if(ret < 0) {
43         perror("accept");
44         return 1;
45     }
46
47     /*接收*/
48     ret = recv(nfd, data, 1024, 0);
49     if(ret < 0) {
50         perror("recv");
51         return 1;
52     }
53     printf("clt said: %s\n", data);
54     close(fd);
55
56     return 0;
57 }

服务器端

 1 #include <stdio.h>
 2 #include <sys/socket.h>
 3 #include <netinet/in.h>
 4 #include <string.h>
 5
 6 //client
 7 int main()
 8 {
 9     int sock_fd = 0;
10     int ret = 0;
11     unsigned char *buf = "hello, hao ara you";
12
13     /*创建一个套接口*/
14     sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
15     if(sock_fd < 0) {
16         perror("socket");
17         return 1;
18     }
19
20     /*服务端信息*/
21     struct sockaddr_in ser;
22     ser.sin_family = AF_INET;
23     ser.sin_port = htons(2009);
24     ser.sin_addr.s_addr = inet_addr("192.168.1.10");
25
26     //建立链接
27     ret = connect(sock_fd, (struct sockaddr *)&ser, 16);
28     if(ret < 0) {
29         perror("connect");
30         return 1;
31     }
32
33     /*发送*/
34     ret = send(sock_fd, buf, strlen(buf), 0);
35     if(ret < 0) {
36         perror("send");
37         return 1;
38     }
39
40     close(sock_fd);
41     return 0;
42 }

客户端

上面程序是基于tcp的简单通信,下面我们利用tcp实现一个服务器多个客户机;要实现一对多,就要使用线程编程,服务器端在不断监听中,如果有连接请求的话,就用通过 accept函数接受并创建一个线程来处理。线程的创建函数为int pthread_create(pthread_t * thread, pthread_attr_t * attr, void * (*start_routine)(void *), void * arg);

  下面是这个程序的源码

 1 #include <stdio.h>
 2 #include <sys/socket.h>
 3 #include <netinet/in.h>
 4 #include <string.h>
 5 #include <pthread.h>
 6
 7 #define PORT 9527
 8
 9 void *function(void *d);//线程要执行的函数
10
11 int main()
12 {
13     /*创建套接口*/
14     pthread_t pid= 0;
15     int nfd = 0;
16     int fd = 0;
17     fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
18     if(fd < 0) {
19         perror("sock");
20         return 1;
21     }
22     /*服务器信息*/
23     struct sockaddr_in ser;
24     ser.sin_family = AF_INET;
25     ser.sin_port = htons(PORT);
26     ser.sin_addr.s_addr = inet_addr("192.168.1.10");
27     struct sockaddr_in clt;
28     int len = 0;
29
30     /*绑定*/
31     int ret = bind(fd, (struct sockaddr *)&ser, 16);
32     if(ret == -1) {
33         perror("bind");
34         return 1;
35     }
36
37     /*监听*/
38     ret = listen(fd, 10);
39     if(ret < 0) {
40         perror("listen");
41         return 1;
42     }
43
44     while(1) {
45         /*接受链接*/
46         nfd = accept(fd, (struct sockaddr *)&clt, &len);
47         if(nfd < 0) {
48             perror("accept");
49             return 1;
50         }
51
52         /*创建一个线程*/
53         ret = pthread_create(&pid, NULL, function, (void *)nfd);
54         if(ret != 0) {
55             perror("pthread_create");
56             return 1;
57         }
58
59         pthread_join(pid, NULL);
60
61         close(nfd);
62     }
63
64     close(fd);
65     return 0;
66 }
67
68 void *function(void *d)
69 {
70     unsigned char buf[1024] = {0};
71     int nfd = (int )d;
72     int ret = 0;
73
74     memset(buf, 0, 1024);
75     ret = recv(nfd, buf, 1024, 0);
76     if(ret < 0) {
77         perror("recv");
78         return NULL;
79     }
80     printf("client said: %s\n", buf);
81
82     ret = send(nfd, "recv ok", 7, 0);
83     if(ret < 0) {
84         perror("send");
85         return NULL;
86     }
87
88
89 }

server

 1 #include <stdio.h>
 2 #include <sys/socket.h>
 3 #include <netinet/in.h>
 4 #include <string.h>
 5
 6 #define PORT 9527
 7
 8 int main(int argc, char **argv)
 9 {
10     if(argc != 3) {
11         printf("using %s <ip address> <message>\n", argv[0]);
12         return 0;
13     }
14     /*创建套接口*/
15     int fd = 0;
16     fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
17     if(fd < 0) {
18         perror("socket");
19         return 1;
20     }
21
22     /*服务器信息*/
23     struct sockaddr_in ser;
24     ser.sin_family = AF_INET;
25     ser.sin_port = htons(PORT);
26     ser.sin_addr.s_addr = inet_addr(argv[1]);
27
28     /*创建链接*/
29     int ret = connect(fd, (struct sockaddr *)&ser, 16);
30     if(ret < 0) {
31         perror("connect");
32         return 1;
33     }
34
35     /*访问*/
36     ret = send(fd, argv[2], strlen(argv[2]), 0);
37     if(ret < 0) {
38         perror("send");
39         return 1;
40     }
41
42     char buf[1024] = {0};
43     ret = recv(fd, buf, 1024, 0);
44     if(ret < 0) {
45         perror("recv");
46         return 1;
47     }
48     printf("server: %s\n", buf);
49     close(fd);
50
51     return 0;
52 }

client

  上面代码需要注意的是,监听程序最大允许接受10个连接请求,如果这十个一直连接不断开的话,后续的连接请求就无法得到处理,所以我们需要在每次请求完毕之后就关闭nfd;下次请求再重新连接;

  第三个程序我们实现基于tcp的聊天程序:

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<string.h>
 4 #include<sys/socket.h>
 5 #include<netinet/in.h>
 6
 7 int main()
 8 {
 9     /*创建套接口*/
10     int  fd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
11     if(fd < 0){
12         perror("socket");
13         exit(EXIT_FAILURE);
14     }
15
16     /*服务端信息*/
17     struct sockaddr_in srv;
18     srv.sin_family = AF_INET;
19     srv.sin_port=htons(9527);
20     srv.sin_addr.s_addr = htonl(INADDR_ANY);
21
22     /*绑定*/
23     int ret = bind(fd,(struct sockaddr *)&srv,sizeof(struct sockaddr ));
24     if(ret < 0){
25         perror("bind");
26         exit(EXIT_FAILURE);
27     }
28     ret = listen(fd,10);
29     if(ret < 0){
30         perror("bind");
31         exit(EXIT_FAILURE);
32     }
33     struct sockaddr_in snd;
34     int snd_len = 0;
35
36     /*接受*/
37     int nfd = accept(fd,(struct sockaddr *)&snd,&snd_len);
38     if(nfd < 0){
39         perror("accpet");
40         exit(EXIT_FAILURE);
41     }
42
43     char data[1024] = {0};
44     char revdata[1024] = {0};
45     /*聊天*/
46     while(1){
47         memset(revdata, 0, 1024);
48         memset(data, 0, 1024);
49         ret = recv(nfd,revdata,1024,0);
50             if(ret < 0){
51               perror("recv");
52               exit(EXIT_FAILURE);
53            }
54
55         printf("client say: %s\n",revdata);
56         if(strcmp(revdata, "end") == 0) {
57             break;
58         }
59
60         ret = read(0,data,1024);
61            if(ret < 0){
62             perror("read");
63             exit(EXIT_FAILURE);
64         }
65         ret = send(nfd,data,1024,0);
66         if(ret < 0){
67             perror("recv");
68             exit(EXIT_FAILURE);
69         }
70
71
72     }
73     close(nfd);
74     close(fd);
75     return 0;
76 }

server

 1 #include <stdio.h>
 2 #include <sys/socket.h>
 3 #include <netinet/in.h>
 4 #include <string.h>
 5 #include <sys/types.h>
 6 #include <unistd.h>
 7
 8 int main()
 9 {
10     /*创建套接口*/
11     int sock_fd = 0;
12     sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
13     if(sock_fd < 0) {
14         perror("socket");
15         return 1;
16     }
17     /*服务端信息*/
18     struct sockaddr_in ser;
19     ser.sin_family = AF_INET;
20     ser.sin_port = htons(9527);
21     ser.sin_addr.s_addr = inet_addr("192.168.1.10");
22
23     /*建立链接*/
24     int ret = connect(sock_fd, (struct sockaddr *)&ser, 16);
25     if(ret == -1) {
26         perror("connect");
27         return 1;
28     }
29
30     /*聊天*/
31     unsigned char data[1024] = {0};
32     unsigned char rec[1024] = {0};
33     while(1) {
34         memset(data, 0, 1024);
35         memset(rec, 0, 1024);
36         int r_size = read(0, data, 1024);
37         if(r_size < 0) {
38             perror("read");
39             return 1;
40         }
41
42         ret = send(sock_fd, data, strlen(data), 0);
43         if(ret < 0) {
44             perror("send");
45             return 1;
46         }
47
48         ret = recv(sock_fd, rec, 1024, 0);
49         if(ret < 0) {
50             perror("recv");
51             return 1;
52         }
53         printf("server said: %s\n", rec);
54     }
55     close(sock_fd);
56     return 0;
57 }

client

上面这个代码存在的缺陷是,发送方跟接收只能发送一句接收一句,不能一次性发送多句,要解决这个问题就要需用到IO多路服用,可以通过这个函数来实现:
  int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);

下面贴出代码:

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<string.h>
 4 #include<sys/socket.h>
 5 #include<netinet/in.h>
 6
 7 int main()
 8 {
 9     /*创建套接口*/
10     int  fd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
11     if(fd < 0){
12         perror("socket");
13         exit(EXIT_FAILURE);
14     }
15
16     /*服务端信息*/
17     struct sockaddr_in srv;
18     srv.sin_family = AF_INET;
19     srv.sin_port=htons(9527);
20     srv.sin_addr.s_addr = htonl(INADDR_ANY);
21
22     /*绑定*/
23     int ret = bind(fd,(struct sockaddr *)&srv,sizeof(struct sockaddr ));
24     if(ret < 0){
25         perror("bind");
26         exit(EXIT_FAILURE);
27     }
28     ret = listen(fd,10);
29     if(ret < 0){
30         perror("bind");
31         exit(EXIT_FAILURE);
32     }
33     struct sockaddr_in snd;
34     int snd_len = 0;
35
36     /*接受*/
37     int nfd = accept(fd,(struct sockaddr *)&snd,&snd_len);
38     if(nfd < 0){
39         perror("accpet");
40         exit(EXIT_FAILURE);
41     }
42
43     fd_set rfds;
44     char data[1024] = {0};
45     char revdata[1024] = {0};
46     /*聊天*/
47     while(1){
48
49         FD_ZERO(&rfds);
50         FD_SET(0,&rfds);
51         FD_SET(nfd,&rfds);
52         ret = select(nfd+1,&rfds,NULL,NULL,NULL);
53         if(FD_ISSET(nfd, &rfds)){
54               ret = recv(nfd,revdata,1024,0);
55                 if(ret < 0){
56                     perror("recv");
57                    exit(EXIT_FAILURE);
58                 }
59
60             printf("client say: %s\n",revdata);
61             if(strcmp(revdata, "end") == 0) {
62                 break;
63             }
64         }
65         if(FD_ISSET(0, &rfds)) {
66             ret = read(0,data,1024);
67                if(ret < 0){
68                 perror("read");
69                 exit(EXIT_FAILURE);
70             }
71             ret = send(nfd,data,1024,0);
72             if(ret < 0){
73                 perror("recv");
74                 exit(EXIT_FAILURE);
75             }
76         }
77         memset(revdata, 0, 1024);
78         memset(data, 0, 1024);
79     }
80     close(nfd);
81     close(fd);
82     return 0;
83 }

server

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    /*创建套接口*/
    int sock_fd = 0;
    sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(sock_fd < 0) {
        perror("socket");
        return 1;
    }
    /*服务端信息*/
    struct sockaddr_in ser;
    ser.sin_family = AF_INET;
    ser.sin_port = htons(9527);
    ser.sin_addr.s_addr = inet_addr("192.168.1.10");

    /*建立链接*/
    int ret = connect(sock_fd, (struct sockaddr *)&ser, 16);
    if(ret == -1) {
        perror("connect");
        return 1;
    }

    /*聊天*/
    fd_set rfds;
    unsigned char data[1024] = {0};
    unsigned char rec[1024] = {0};
    while(1) {
        memset(data, 0, 1024);
        memset(rec, 0, 1024);
        FD_ZERO(&rfds); //清空
        FD_SET(0,&rfds);//(标准输入)
        FD_SET(sock_fd,&rfds);//添加监听描述符(套接字)
        /*多路复用IO*/
        ret = select(sock_fd+1,&rfds,NULL,NULL,NULL);

        if(FD_ISSET(0, &rfds)){//监听键盘是否有输入,执行接收
            int r_size = read(0, data, 1024);
            if(r_size < 0) {
                perror("read");
                return 1;
            }
            ret = send(sock_fd, data, strlen(data), 0);
            if(ret < 0) {
                perror("send");
                return 1;
            }
        }

        if(FD_ISSET(sock_fd, &rfds)) {//监听sock_fd是否有输入,执行接收
            ret = recv(sock_fd, rec, 1024, 0);
            if(ret < 0) {
                perror("recv");
                return 1;
            }
            printf("server said: %s\n", rec);
        }
    }
    close(sock_fd);
    return 0;
}

client

    

  

时间: 2024-10-31 13:48:45

网络编程之套接字(tcp)的相关文章

[python] 网络编程之套接字Socket、TCP和UDP通信实例

很早以前研究过C#和C++的网络通信,参考我的文章: C#网络编程之Tcp实现客户端和服务器聊天 C#网络编程之套接字编程基础知识 C#网络编程之使用Socket类Send.Receive方法的同步通讯 Python网络编程也类似.同时最近找工作笔试面试考察Socket套接字.TCP\UDP区别比较多,所以这篇文章主要精简了<Python核心编程(第二版)>第16章内容.内容包括:服务器和客户端架构.套接字Socket.TCP\UDP通信实例和常见笔试考题. 最后希望文章对你有所帮助,如果有不

TCP/IP网络编程之套接字类型与协议设置

套接字与协议 如果相隔很远的两人要进行通话,必须先决定对话方式.如果一方使用电话,另一方也必须使用电话,而不是书信.可以说,电话就是两人对话的协议.协议是对话中使用的通信规则,扩展到计算机领域可整理为"计算机间对话必备通信规则" 在TCP/IP网络编程之网络编程和套接字这一章中,我们已经介绍了如何创建套接字,但为了完全理解该函数,此处将继续展开讨论 #include <sys/socket.h> int socket(int domain, int type, int pr

Linux网络编程——原始套接字实例:简单版网络数据分析器

通过<Linux网络编程--原始套接字编程>得知,我们可以通过原始套接字以及 recvfrom( ) 可以获取链路层的数据包,那我们接收的链路层数据包到底长什么样的呢? 链路层封包格式 MAC 头部(有线局域网) 注意:CRC.PAD 在组包时可以忽略 链路层数据包的其中一种情况: unsigned char msg[1024] = { //--------------组MAC--------14------ 0xb8, 0x88, 0xe3, 0xe1, 0x10, 0xe6, // dst

Linux网络编程——原始套接字实例:MAC 头部报文分析

通过<Linux网络编程——原始套接字编程>得知,我们可以通过原始套接字以及 recvfrom( ) 可以获取链路层的数据包,那我们接收的链路层数据包到底长什么样的呢? 链路层封包格式 MAC 头部(有线局域网) 注意:CRC.PAD 在组包时可以忽略 链路层数据包的其中一种情况: 1 unsigned char msg[1024] = { 2 //--------------组MAC--------14------ 3 0xb8, 0x88, 0xe3, 0xe1, 0x10, 0xe6,

Python网络编程—socket套接字编程(TCP)

套接字介绍 1.套接字 : 实现网络编程进行数据传输的一种技术手段 2.Python实现套接字编程:import socket 3.套接字分类 流式套接字(SOCK_STREAM): 以字节流方式传输数据,实现tcp网络传输方案.(面向连接--tcp协议--可靠的--流式套接字) 数据报套接字(SOCK_DGRAM):以数据报形式传输数据,实现udp网络传输方案.(无连接--udp协议--不可靠--数据报套接字) tcp套接字 服务端流程 1.创建套接字 sockfd=socket.socket

网络编程--Socket(套接字)

网络编程 网络编程的目的就是指直接或间接地通过网络协议与其他计算机进行通讯.网络编程中 有两个主要的问题,一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后 如何可靠高效的进行数据传输.在TCP/IP协议中IP层主要负责网络主机的定位,数据传输的 路由,由IP地址可以唯一地确定Internet上的一台主机.而TCP层则提供面向应用的可靠的 或非可靠的数据传输机制,这是网络编程的主要对象,一般不需要关心IP层是如何处理数据 的. 目前较为流行的网络编程模型是客户机/服务器(C/S)结构

《网络编程》套接字编程简介

本节介绍的套接字是可以实现不同计算机之间的远程进程间通信.套接口是网络进程的 ID,在网络中每一个节点都有一个网络地址,也就是 IP 地址,两个进程间通信时,首先要确定各自所在网络节点的网络地址.但是,网络地址只要确定进程所在的计算机,由于一台计算机上同时可能有多个网络进程,所以仅凭网络地址还不能确定是网络中的哪一个进程,因此套接口中还需要其他信息,也就是端口.在一台计算机中,一个端口号只能分配给一个进程,所以,进程和端口之间是一一对应的关系.因此,使用端口号和网络地址的组合就能唯一地确定整个网

网络编程之套接字socket

目录 socket套接字 引子 为何学习socket一定要先学习互联网协议 socket是什么 套接字类型 基于文件类型的套接字家族 基于网络类型的套接字家族 套接字工作流程 基于TCP的套接字 简单通信 加上链接循环与通信循环 基于UDP的套接字 UDP的套接字下的简单通信 UDP协议支持并发 粘包现象 什么是粘包 两种情况下会发生粘包 解决粘包问题的处理方法 简单方法(不推荐使用) 牛逼方法(利用struct模块打包报头) socketserver模块(实现并发) socketserver模

专题七.网络编程之套接字Socket、TCP和UDP通信实例

https://blog.csdn.net/Eastmount/article/details/48909861 找工作笔试面试考察Socket套接字.TCP\UDP区别比较多,所以这篇文章主要精简了<Python核心编程(第二版)>第16章内容.内容包括:服务器和客户端架构.套接字Socket.TCP\UDP通信实例和常见笔试考题. https://www.cnblogs.com/alex3714/articles/5227251.html 1.Socket语法及相关 2.SocketSer