精华内容
下载资源
问答
  • TCP网络编程

    千次阅读 2019-01-18 14:20:17
     从下往上依次是物理层(电路,布线)-数据链路层(交换机)-网络层(tcp/ip,路由器)-传输层-会话层-表示层(编码,解码,加密,解密,压缩,解压缩)-应用层(http),但是tcp/ip模型是网络接口层-网络层-传输层...

    一、网络的七层模型

           从下往上依次是物理层(电路,布线)-数据链路层(交换机)-网络层(tcp/ip,路由器)-传输层-会话层-表示层(编码,解码,加密,解密,压缩,解压缩)-应用层(http),但是tcp/ip模型是网络接口层-网络层-传输层-应用层

    二、三次握手和四次挥手(详解见另一篇TCP详解博文

          1.  三次握手:

             (1) 客户端向网络服务器端发送请求 (你在吗?)

             (2) 服务器端回应客户端的请求 (我在)

             (3) 服务器端向客户端发送请求 (我在,你在吗?)

          2. 四次挥手

              (1) 客户端向服务器端发送请求 (我要挂了)

              (2) 服务器端回应客户端 (嗯)

              (3) 服务器端回应客户端 (那我挂了)

              (4) 客户端回应服务器端 (嗯,好)

    三、常用的InetAddress的主要函数

    package com.study.test;
    
    import java.io.IOException;
    import java.net.InetAddress;
    
    public class NetTest {
    
        public static void main(String[] args) throws IOException {
            InetAddress ia = InetAddress.getLocalHost();
            System.out.println(ia.getHostName());// 获得本机名字
            System.out.println(InetAddress.getByName(ia.getHostName()));// 通过名字查询到ip地址
            byte[] b = new byte[4];
            b = ia.getAddress();// 以字节的形式存放的地址
            System.out.println(ia.getHostAddress());// 以字符串形式列出的ip地址
    
        }
    
    }

    输出结果:

    xx
    xx/192.168.152.1
    192.168.152.1

    四、tcp编程服务端与客户端通讯

          1. 服务端代码

    package com.study.test;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.Scanner;
    
    /**
     * 编程实现tcp通讯服务端
     * 
     * @author THINKPAD
     *
     */
    public class NetServer {
    
        public static void main(String[] args) throws IOException {
            // 1 建立服务端socket
            ServerSocket ss = new ServerSocket(60000);// 1、有效没有指明ip地址,则本网卡对应的所有ip地址全部
            // 通信的时候一定要有目标端口号,如果没有,则补救bind
            // ServerSocket ss=new ServerSocket();
            // SocketAddress sa=new InetSocketAddress(60000);
            // ss.bind(sa);
            // 2 进行接收连接
            Socket s = ss.accept(); // 阻塞等待,等待三次握手 1 syn 2 ack syn 3 ack ,一旦握手成功,形成一个通道
            System.out.println(s.getPort() + "连接进来了"); // 如果tcp每次发送信息,对方一定要确认收到的,这样可以保证数据不丢失
    
            while (true) {
                // 3 接收传送的信息,通过网络流/节点流
                InputStream is = s.getInputStream();
                InputStreamReader isr = new InputStreamReader(is);
                char[] cArray = new char[20];
                int iRead = isr.read(cArray);// 阻塞函数,一定要接收到数据 比如:in.read()一定要从键盘缓冲区获得数据,而这个等待是一定要从服务器获得数据
                if (iRead == -1)
                    break;
                System.out.println("得到的字节数:" + iRead);// 返回字节数
                System.out.println("收到的信息是" + new String(cArray, 0, iRead));
                // 3.1 回复信息
                OutputStream os = s.getOutputStream();
                Scanner sc = new Scanner(System.in);
                String sSend = sc.nextLine();
                os.write(sSend.getBytes());
            }
            // 4 关闭 结束之后就会发生4次挥手 1 fin ack 2 ack 3 fin ack 4 ack
            ss.close();
            s.close();
    
        }
    
    }

    2. 客户端代码

    package com.study.test;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.net.Socket;
    import java.util.Scanner;
    
    /**
     * 编程实现tcp通讯的客户端
     * 
     * @author THINKPAD
     *
     */
    public class NetClient {
        public static void main(String[] args) throws IOException {
            // 1 建立客户端socket ,建立一个通道
            Socket s = new Socket("192.168.152.1", 60000);
            while (true) {
                // 2.1 先发送信息
                OutputStream os = s.getOutputStream();
                Scanner sc = new Scanner(System.in);
                String sSend = sc.nextLine();
                os.write(sSend.getBytes());
    
                // 2.2 接收传送的信息,通过网络流/节点流
                InputStream is = s.getInputStream();
                InputStreamReader isr = new InputStreamReader(is);
                char[] cArray = new char[20];
                int iRead = isr.read(cArray);// 阻塞函数,一定要接收到数据 比如:in.read()一定要从键盘缓冲区获得数据,而这个等待是一定要从服务器获得数据
                if (iRead == -1)
                    break;
                System.out.println("得到的字节数:" + iRead);// 返回字节数
                System.out.println("收到的信息是" + new String(cArray, 0, iRead));
            }
            // 3 关闭 结束之后就会发生4次挥手 1 fin ack 2 ack 3 fin ack 4 ack
            s.close();
    
        }
    
    }

     

     

     

     

     

     

     

     

     

     

    展开全文
  • TCP网络编程之服务器多线程实现   1、TCP网络编程之服务器多线程实现的背景 (1)假设我们的一个服务器供很多客户端使用,而这些客户端都是来上传文件的。那么,如果服务器端是单线程实现的,则就会出现”先到的...

    TCP网络编程之服务器多线程实现

     

    1、TCP网络编程之服务器多线程实现的背景

    (1)假设我们的一个服务器供很多客户端使用,而这些客户端都是来上传文件的。那么,如果服务器端是单线程实现的,则就会出现”先到的客户端优先使用服务器端资源“的现象,即让客户端依次排队使用服务器,这是不符合常理的。常理应该是:不同的客户端会抢占服务器的资源,哪个客户端的带宽大、哪个客户端需要上传的资源小,哪个客户端就会先上传成功。

    (2)为了解决这个问题,我们在服务器端使用了多线程的实现方式。即:每来一个客户端的请求就会为该客户端创建一个线程供它自己去执行上传操作。注意:多线程之间会相互抢占同一个服务器的资源,这要看这些多线程的优先级或者其他本领了。

    2、TCP网络编程之服务器多线程实现

    (1)服务器端:多线程实现——UploadServer类

    package cn.itcast_15;
    import java.io.IOException;
    import java.net.ServerSocket;
    import java.net.Socket;
    public class UploadServer {
    	public static void main(String[] args) throws IOException {
    		// 创建服务器Socket对象
    		ServerSocket ss = new ServerSocket(11111);
    		while (true) {
    			Socket s = ss.accept();
                            //每来一个客户端的请求都为这个客户端创建一个线程
    			new Thread(new UserThread(s)).start();
    		}
    	}
    }

    (2)服务器端:多线程实现——UserTread类

    package cn.itcast_15;
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    import java.net.Socket;
    public class UserThread implements Runnable {
    	private Socket s;
    	public UserThread(Socket s) {
    		this.s = s;
    	}
    	@Override
    	public void run() {
    		try {
    			// 封装通道内的流
    			BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
    			// 封装文本文件。为了防止名称冲突
    			String newName = System.currentTimeMillis() + "Copy.java" + ".java";
    			BufferedWriter bw = new BufferedWriter(new FileWriter(newName));
    			String line = null;
    			while ((line = br.readLine()) != null) { // 阻塞
    				bw.write(line);
    				bw.newLine();
    				bw.flush();
    			}
    			// 给客户端一个反馈
    			BufferedWriter bwServer = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
    			bwServer.write("文件上传成功");
    			bwServer.newLine();
    			bwServer.flush();
    			// 释放资源
    			bw.close();
    			s.close();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    }
    

    (3)客户端:保持不变——UploadClient类

    package cn.itcast_15;
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.FileReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    import java.net.Socket;
    public class UploadClient {
    	public static void main(String[] args) throws IOException {
    		// 创建客户端Socket对象
    		Socket s = new Socket("192.168.12.92", 11111);
    		// 封装文本文件
    		// BufferedReader br = new BufferedReader(new FileReader(
    		// "InetAddressDemo.java"));
    		BufferedReader br = new BufferedReader(new FileReader("ReceiveDemo.java"));
    		// 封装通道内流
    		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
    		String line = null;
    		while ((line = br.readLine()) != null) { // 阻塞
    			bw.write(line);
    			bw.newLine();
    			bw.flush();
    		}
    		// Socket提供了一个终止方法,它会通知服务器你别等了,我没有数据过来了
    		s.shutdownOutput();
    		// 接收服务器给出的反馈信息
    		BufferedReader brClient = new BufferedReader(new InputStreamReader(s.getInputStream()));
    		String client = brClient.readLine(); // 阻塞
    		System.out.println(client);
    		// 释放资源
    		br.close();
    		s.close();
    	}
    }
    

     

    2、Java网络编程总结

    1:网络编程(理解)
        (1)网络编程:用Java语言实现计算机间数据的信息传递和资源共享
        (2)网络编程模型
        (3)网络编程的三要素
            A:IP地址
                a:点分十进制
                b:IP地址的组成
                c:IP地址的分类
                d:dos命令
                e:InetAddress
            B:端口
                是应用程序的标识。范围:0-65535。其中0-1024不建议使用。
            C:协议
                UDP:数据打包,有限制,不连接,效率高,不可靠
                TCP:建立数据通道,无限制,效率低,可靠
        (3)Socket机制
            A:通信两端都应该有Socket对象
            B:所有的通信都是通过Socket间的IO进行操作的
        (4)UDP协议发送和接收数据(掌握 自己补齐代码)
            发送:
                创建UDP发送端的Socket对象
                创建数据并把数据打包
                发送数据
                释放资源
                
            接收:
                创建UDP接收端的Socket对象
                创建数据包用于接收数据
                接收数据
                解析数据包
                释放资源
        (5)TCP协议发送和接收数据(掌握 自己补齐代码)
            发送:
                创建TCP客户端的Socket对象
                获取输出流,写数据
                释放资源
                
            接收:
                创建TCP服务器端的Socket对象
                监听客户端连接
                获取输入流,读取数据
                释放资源
        (6)案例:
            A:UDP
                a:最基本的UDP协议发送和接收数据
                b:把发送数据改进为键盘录入
                c:一个简易聊天小程序并用多线程改进
            B:TCP
                a:最基本的TCP协议发送和接收数据
                b:服务器给出反馈
                c:客户端键盘录入服务器控制台输出
                d:客户端键盘录入服务器写到文本文件
                e:客户端读取文本文件服务器控制台输出
                f:客户端读取文本文件服务器写到文本文件
                g:上传图片
                h:多线程改进上传文件

     

    展开全文
  • tcp网络编程 tcp网络编程步骤: 由于tcp传输特点是可靠有连接,那么就有 1.客户端向服务端发送连接请求(SYN), 2.服务端接受请求并向客户端发送(SYN+ACK); 3.客户端向服务端回复ACK表明他知道服务端同意连接...

    tcp网络编程
    tcp网络编程步骤:
    由于tcp传输特点是可靠有连接,那么就有
    1.客户端向服务端发送连接请求(SYN),
    2.服务端接受请求并向客户端发送(SYN+ACK);
    3.客户端向服务端回复ACK表明他知道服务端同意连接。
    以上三个步骤就是三次握手。
    服务端编程步骤:
    1.创建套接字
    2.为套接字绑定地址信息
    3.监听:开始接受服务端的连接请求
    4.获取连接建立成功的新socket
    5.发送数据
    6.接受数据
    1.创建套接字

    #include <sys/socket.h>
    int socket(int domain, int type, int protocol);
    domain:地址域
    		 AF_INET :ipv4协议
    type: 套接字类型
    		SOCK_STREAM 流式套接字
    		SOCK_DGRAM  数据报套接字
    protocol :协议类型 
    		如果是0,则表示默认;流式套接字默认tcp协议,报式套接字默认udp协议
    		流式套接字: IPPROTO_TCP 6 
    		报式套接字:IPPROTO_UDP 17  
    如:socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    返回值:成功:套接字描述符 
    	   失败:-1						
    

    2.为socket绑定地址信息

     #include <sys/socket.h>
     int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
     参数: sockfd: socket描述符
     	   addr :socket绑定的地址
     	   addrlen :地址信息长度
     返回值:成功:0(网卡操作那个进程),失败 -1
     功能:将参数sockfd和addr绑定在一起,使sockfd这个用于网络通讯的文件描述符监听addr所描述的地址和端口号。
     sockaddr结构:
     struct sockaddr {
                   sa_f  amily_t sa_family;
                   char        sa_data[14];
                    }
    虽然bind里参数是sockaddr,但是真正在基于IPV4编程时,使用的结构体是sockaddr_in;这个结构体里主要有三部分信息:地址类型,端口号,IP地址。
    sockaddr_in在头文件#include<netinet/in.h>或#include<arpa/inet.h>中定义。该结构体解决了sockaddr的缺陷,把port和addr 分开储存在两个变量中,如下: 
    structsockaddr_in{
    
    short           sin_family;//AF_INET(地址族)PF_INET(协议族)
    
    unsigned short  sin_port;/*Portnumber(必须要采用网络数据格式,普通数字可以用htons()函数转换成网络数据格式的数字)*/
    
    struct in_addr  sin_addr;//32位IP地址
    
    unsigned char   sin_zero[8];//没有实际意义,只是为了跟SOCKADDR结构在内存中对齐*/
    
    };
    该结构体中提到的另一个结构体in_addr定义如下,它用来存放32位IP地址:
    typedef uint32_t in_addr_t;
    struct in_addr
    {
    	in_addr_t s_addr;
    };   
    in_addr用来表示一个IPV4的IP地址,其实是一个32位整数。   
    

    客户端不推荐手动绑定地址信息 ,因为绑定有可能因为特殊原因失败,但是客户端具体使用哪个地址和端口都可以,只要能把数据发送出去,所以客户端程序不手动绑定地址,直至发送数据时,操作系统检测到socket没有绑定地址,会自动选择合适的地址和端口为socket绑定地址,这种数据一般不会出错。
    3.监听(服务端监听后才可以接受客户端连接请求)

    #include <sys/types.h>          /* See NOTES */
    #include <sys/socket.h>
    int listen(int sockfd, int backlog);
    
    listen()声明sockfd处于监听状态,并且最多允许backlog个客户端处于连接等待状态,如果接受到更多的连接请求就忽略,一般是5,即代表最大同时并发连接数为5,这个数字并不是tcp最大建立连接数。(文章后面会讲述tcp最大建立连接数)
    返回值:成功: 0  失败 -1
    

    4.accept():获取新建立的socket

    #include <sys/socket.h>
    int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
    sockfd : socket描述符
    addr  :新建立连接的客户端地址信息
    addrlen :地址信息长度
    返回值:成功:返回新的socket连接描述符
    	   失败:-1
    accept是阻塞型函数,如果连接成功的队列没有新的连接,将会一直阻塞等待新的客户端连接
    

    参数sockfd和返回值newsockfd区别:
    sockfd :所有连接请求的数据发送到socket这个缓冲区(包括服务端ip和port),然后进行处理(为这个新建立连接的客户端新建立一个socket);
    newsockfd: 连接建立成功后,连接成功的客户端发送的数据都发送到这个新的socket缓冲区(包括服务端ip port和建立连接客户端ip port)。
    5.发送数据

     #include <sys/types.h>
     #include <sys/socket.h>
     ssize_t send(int sockfd, const void *buf, size_t len, int flags);
     flag :  0默认阻塞发送数据
    

    由于accept返回的socket描述符中有客户端ip和port,所以参数中就没有struct sockaddr_in 和 addrlen,这是和udp发送数据的区别。同理,tcp和udp接受数据函数参数不同。

    6.接受数据

    #include <sys/types.h>
    #include <sys/socket.h>
    ssize_t recv(int sockfd, void *buf, size_t len, int flags);
    sockfd: 里面已经包含从哪儿接受数据信息,是新的sockfd
    buf:用于接受数据
    len :用于接受数据长度
    flags:  0  默认 阻塞式接收 
    返回值 : 错误 : -1
            连接关闭 ; 0
            实际接受数据 >0
    

    7.关闭socket描述符

    要在任意可能退出的地方关闭对应的socket描述符。
    tcp服务端代码

    // tcp 服务端代码
    //1.创建套接字
    //2.绑定地址信息
    //3.监听:监听之后获取新的socket连接
    //4.获取新的socket连接
    //5.接受数据
    //6.发送数据
    //7.关闭socket描述符
    #include<stdio.h>
    #include<errno.h>
    #include<string.h>
    #include<sys/socket.h>
    #include<arpa/inet.h>
    #include<netinet/in.h>
    
    int main(int argc,char *argv[]) //将需要绑定的IP地址和port在命令行输出来
    {
            if(argc!=3)
            {   
                    printf("Usage:ip and port\n");
            }   
            //1.创建套接字
            int sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
            if(sockfd<0)
            {   
                    perror("sockfd error");
                    return -1; 
            }   
            //2.绑定地址信息
            // int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
            struct sockaddr_in ser_addr;
            ser_addr.sin_family=AF_INET;
            ser_addr.sin_addr.s_addr=inet_addr(argv[1]);
            ser_addr.sin_port=(htons)(atoi(argv[2])); 
            int len=sizeof(struct sockaddr_in);
            int ret=bind(sockfd,(struct sockaddr*)&ser_addr,len);
            if(ret<0)
     {
                    perror("binf error");
                    close(sockfd);
                    return -1;
            }
    
            //3.监听
            // int listen(int sockfd, int backlog);
            if(listen(sockfd,5)<0)//开始监听,接受客户端的连接请求,最大同时并发连接数为5
            {
                    perror("listen error");
                    close(sockfd);
                    return -1;
            }
            //连接建立成功后,服务端会新建立一个socket
            while(1)
            {  //用while循环当一个连接断开后,可以重新获取新的socket
                    //4.获取新建立的socket
                    struct sockaddr_in cli_addr;
                    len=sizeof(struct sockaddr_in);
                    // int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
                    int newsockfd=accept(sockfd,(struct sockaddr*)&cli_addr,&len);//获取成功,返回新的socket描述符
                    if(newsockfd<0)
                    {
                            perror("newsockfd error");
                            return -1;
                    }
                    //连接建立成功:
                    printf("new con:%s %d\n",(inet_ntoa)(cli_addr.sin_addr),ntohs(cli_addr.sin_port));
                    while(1)  //用循环是保证服务端可以和一个客户端可以多次聊天
                    {
                            //5.发送数据 
                            //tcp协议:获取新的socket描述符后,新的socket里包含了服务端和客户端的地址信息,所以发送和接受数据没有先后之分
                            // ssize_t send(int sockfd, const void *buf, size_t len, int flags);
                            char buff[1024]={0};
                            printf("please send data:");
     scanf("%s",buff);
                            ret=send(newsockfd,buff,strlen(buff),0); //阻塞发送数据 
                            if(ret<0)
                            {
                                    perror("send error");
                                    close(newsockfd);
                                    return -1;
                            }
                            //6.接受数据
                            //ssize_t recv(int sockfd, void *buf, size_t len, int flags);
                            memset(buff,0x00,1024);
                            len=recv(newsockfd,buff,1023,0);//0默认阻塞接受数据
                            if(len<0)//小于0接受失败
                            {
                                    perror("recv error");
                                    close(newsockfd);
                                    continue;
                            }
                            else if(len==0)//等于0对端将连接断开
                            {
                                    perror("peer has performed an orderly shutdown");
                                    close(newsockfd);
                                    continue;
                            }
                            printf("[%s:%d]->%s\n",inet_ntoa(cli_addr.sin_addr),ntohs(cli_addr.sin_port),buff);
                    }
                    close(newsockfd);
            }
            close(sockfd);
            return -1;
    }
    

    tcp客户端编程步骤
    1.创建套接字
    2.绑定地址信息(没有必要调用bind()绑定信息,否则一台机器上启动多个客户端,就会出现端口号被占用而导致不能正常连接)
    3.向服务端发起连接请求
    4.接受数据
    5.发送数据
    6.关闭
    创建套接字、发送数据、接受数据即挂壁和服务端一样。
    3.向服务端发送连接请求

    int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    addr:要连接的服务端地址
    addrlen :地址信息长度
    返回值: 成功; 0  失败 -1
    

    客户端代码:

    //tcp 客户端代码
    //1.创建套接字
    //2.绑定地址信息
    //3.向服务端发送连接请求
    //4.发送数据
    //5.接受数据
    //6.关闭socket描述符
    
    #include<stdio.h>
    #include<error.h>
    #include<arpa/inet.h>
    #include<netinet/in.h>
    #include<string.h>
    #include<sys/socket.h>
    #include<stdlib.h>
    
    int main(int argc,char* argv[])
    {
            if(argc!=3)
            {   
                    printf("Usage ip and port\n");
            }   
            //1.创建套接字
            int sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
            if(sockfd<0)
            {   
                    perror("socket error");
                    return -1; 
            }    
            //2.绑定地址信息(不推荐手动写绑定信息代码)
            //3.向服务端发送连接请求
            //int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
            struct sockaddr_in ser_addr;
            ser_addr.sin_family=AF_INET;
            ser_addr.sin_port=(htons)(atoi(argv[2]));  //htons :主机字节序转换成网络字节序
            ser_addr.sin_addr.s_addr=(inet_addr)(argv[1]);//因为argv[]是char*,用atoi使字符串转成整型
            int len=sizeof(struct sockaddr_in);
    int ret=connect(sockfd,(struct sockaddr*)&ser_addr,len);
            if(ret<0)
            {
                    perror("connect error");
                    close(sockfd);
                    return -1;
            }
            //连接成功,socket描述符里有服务端和客户端IP地址和port
            while(1)
            {
                    //4.接受数据
                    //ssize_t recv(int sockfd, void *buf, size_t len, int flags);
                    char buff[1024]={0};
                    ret=recv(sockfd,buff,1023,0);//默认阻塞接受数据
                    if(len<0)//小于0接受失败
                    {
                            perror("recv error");
                            close(sockfd);
                            continue;
                    }
                    else if(len==0)//等于0对端将连接断开
                    {
                            perror("peer has performed an orderly shutdown");
                            close(sockfd);
                            continue;
                    }
                    // net_ntoa :网络字节序转换成点分十进制IP
                    //ntohs  :主机字节序转换成网络字节序
                    printf("[%s:%d]say:%s\n",(inet_ntoa)(ser_addr.sin_addr),(ntohs)(ser_addr.sin_port),buff);
                    //4.发送数据
                    // ssize_t send(int sockfd, const void *buf, size_t len, int flags);
                    memset(buff,0x00,1024);
      printf("please send\n");
                    scanf("%s",buff);
                    ret=send(sockfd,buff,strlen(buff),0); //默认阻塞接受数据
                    if(ret<0)
                    {
                            perror("send error");
                            close(sockfd);
                            return -1;
                    }
            }
            close(sockfd);
            return 0;
    }
    

    客户端:
    在这里插入图片描述
    服务端:
    在这里插入图片描述
    当客户端ctrl+c断开连接后,服务端会提示对端已关闭,这时会有新的客户端建立连接。
    listen参数和tcp最多建立连接数
    int listen(int sockfd, int backlog);
    backlog:
    协议栈使用一个队列:这个队列的大小由listen系统调用的backlog参数决定。当一个syn包到达后,服务端协议栈回复syn+ack,然后将这个socket加入这个队列。当客户端第三次握手的ack包到达后,再将这个socket的状态改为ESTABLISHED状态。这也就意味着这个队列可以可以容纳两种不同状态的socket:SYN RECEIVED和 ESTABLISHED,而只有后者可以被accept调用返回。当队列中的连接数(socket)达到backlog个后,系统收到syn将不再回复syn+ack。这种情况下协议栈通常仅仅是将syn包丢掉,而不是回复rst报文,从而让客户端可以重试。
    tcp最大连接数:
    用ulimit -n 结果是1024,这表示当前用户的每个进程最多允许同时打开1024个文件,这1024个文件需要除去每个进程必然打开的标准输入、标准输出、标准错误、服务器监听socket,进程间通讯的unix域socket等文件,那么剩下可用于客户端socket连接的文件数就只有大概1024-10=1014个,即在缺省条件下,基于linux的通讯程序最多允许同时1014个TCP并发连接。

    展开全文
  • 基于Linux的TCP网络编程

    千次阅读 2013-11-12 13:04:29
    基于Linux的TCP网络编程 一.Linux下TCP编程框架 TCP网络编程的流程包含服务器和客户端两种模式。服务器模式创建一个服务程序,等待客户端用户的连接,接收到用户的连接请求后,根据用户的请求...

    基于Linux的TCP网络编程

    一.Linux下TCP编程框架

    TCP网络编程的流程包含服务器和客户端两种模式。服务器模式创建一个服务程序,等待客户端用户的连接,接收到用户的连接请求后,根据用户的请求进行处理;客户端模式则根据目的服务器的地址和端口进行连接,向服务器发送请求并对服务器的响应进行数据处理。

    1.服务器端程序包括

    Ø  建立套接字( socket())

    Ø  套接字与端口的绑定(bind())

    Ø  设置服务器的侦听连接(listen())

    Ø  接收客户端连接(accept())

    Ø  接收和发送数据(send(),recv())

    Ø  关闭套接字(close())

    2.说明

    1>套接字初始化过程中,根据用户对套接字的需求来确定套接字的选项。按照用户定义的网络类型,协议类型和具体的协议标号等参数来定以socket()函数。系统根据用户的需求生成一个套接字文件描述符供用户使用。

    2>套接字与端口的绑定过程中,将套接字与一个地址结构进行绑定。绑定之后,套接字所代表IP地址和端口地址及协议类型等参数按照绑定值进行操作。

    3>由于一个服务器需要满足多个客户端的连接请求,而服务器在某个时间仅能处理有限个数的客户端连接请求,所以服务器需要设置服务器端排队队列的长度。

    4>在客户端发送连接请求之后,服务器需要接收客户端的连接,然后才能进行其他的处理。

    5>在服务器接收客户端请求之后,可以从套接字文件描述符中读取数据或者向文件描述符发送数据。接收数据后服务器按照定义的规则对数据进行处理,并将结果发送给客户端。

    6>当服务器处理完数据,要结束与客户端的通信过程的时候,需要关闭套接字连接

    2.客户端程序包括

    Ø  建立套接字(socket())

    Ø  连接服务器(connect())

    Ø  读写网络数据(send(),recv())

    Ø  关闭套接字(close())

    3.服务器端和客户端程序的区别

    客户端程序和服务器端程序不同之处是客户端在建立套接字之后可以不进行地址绑定,而是直接连接服务器端。

    服务器端有listen()和accept()两个函数,而客户端不需要这两个函数。

    二.基于Linux的TCP套接字函数

    1. socket

    1> 函数原型:

    int socket(int domain,int type,int protocol)

    2> 函数功能:

    函数socket()用于创建一个套接字描述符。

    3> 形参:

    Ø  domain:用于指定创建套接字所使用的协议族,在头文件

    <linux/socket.h>中定义。有时候程序中会使用PF_INET,在头文件中AF_INET和PF_INET的数值是一致的。

    常见的协议族如下:

    AF_UNIX:创建只在本机内进行通信的套接字。

    AF_INET:使用IPv4TCP/IP协议

    AF_INET6:使用IPv6 TCP/IP协议

    说明:

    AF_UNIX只能用于单一的UNIX系统进程间通信,而AF_INET是针对Interne的,因而可以允许在远程主机之间通信。一般把它赋为AF_INET。

    Ø  type:指明套接子通信的类型,对应的参数如下

    SOCK_STREAM:创建TCP流套接字

    SOCK_DGRAM:创建UDP数据报套接字

    SOCK_RAW:创建原始套接字

    Ø  protocol:指定某个协议的特定类型

    参数protocol通常设置为0,表示通过参数domain指定的协议族和参数type指定的套接字类型来确定使用的协议。当为原始套接字时,系统无法唯一的确定协议,此时就需要使用使用该参数指定所使用的协议。

    4> 返回值:执行成功后返回一个新创建的套接字;若有错误发生则返回一个-1,错误代码存入errno中。

    5> 举例:调用socket函数创建一个UDP套接字

    int sock_fd;

    sock_fd = socket(AF_INET,SOCK_DGRAM,0);

    if(sock_fd< 0){

           perror(“socket”);

           exit(1);

    }

    2. bind

    1> 函数原型:

    int bind(int sockfd,struct sockaddr *my_addr,socklen_t addrlen)

    2> 函数功能

    函数bind()的作用是将一个套接字文件描述符与地址和端口绑定。

    3> 形参:

    Ø  sockfd:sockfd是调用socket函数返回的文件描述符;

    Ø  addrlen是sockaddr结构的长度。

    Ø  my_addr: 是一个指向sockaddr结构的指针,它保存着本地套接字的地址(即端口和IP地址)信息。不过由于系统兼容性的问题,一般不使用这个结构,而使用另外一个结构(structsockaddr_in)来代替

    4> 套接字地址结构:

    (1)struct sockaddr:

    结构struct  sockaddr定义了一种通用的套接字地址,它在

    sys/socket.h 中定义。

    struct sockaddr{

           unsigned short  sa_family;/*地址类型,AF_XXX*/

           char          sa_data[14];/*14字节的协议地址*/

    }

    a. sin_family:表示地址类型,对于使用TCP/IP协议进行的网络编程,该值只能是AF_INET.

    b. sa_data:存储具体的协议地址。

    (2)sockaddr_in

    每种协议族都有自己的协议地址格式,TCP/IP协议组的地址格式为结构体struct sockaddr_in,它在netinet/in.h头文件中定义。

    structsockaddr_in{

       unsigned short  sin_family;/*地址类型*/

       unsigned short  sin_port;/*端口号*/

       struct in_addr   sin_addr;/*IP地址*/

       unsigned char  sin_zero[8];/*填充字节,一般赋值为0*/

    }

    a. sin_family:表示地址类型,对于使用TCP/IP协议进行的网络编程,该值只能是AF_INET.

    b. sin_port:是端口号

    c. sin_addr:用来存储32位的IP地址。

    d. 数组sin_zero为填充字段,一般赋值为0.

    e. struct in_addr的定义如下:

    structin_addr{

                         unsigned long s_addr;

    }

    结构体sockaddr的长度为16字节,结构体sockaddr_in的长度为16字节。可以将参数my_addr的sin_addr设置为INADDR_ANY而不是某个确定的IP地址就可以绑定到任何网络接口。对于只有一IP地址的计算机,INADDR_ANY对应的就是它的IP地址;对于多宿主主机(拥有多个网卡),INADDR_ANY表示本服务器程序将处理来自所有网络接口上相应端口的连接请求

    5> 返回值:

    函数成功后返回0,当有错误发生时则返回-1,错误代码存入errno中。

    6>举例:调用socket函数创建一个UDP套接字

    struct sockaddr_in addr_serv,addr_client;/*本地的地址信息*/

    memset(&serv_addr,0,sizeof(structsockaddr_in));

    addr_serv.sin_family= AF_INET;/*协议族*/

    addr_serv.sin_port= htons(SERV_PORT);/*本地端口号*/

    addr_serv.sin_addr.s_addr= htonl(INADDR_ANY); /*任意本地地址*/
    /*套接字绑定*/

    if(bind(sock_fd,(structsockaddr *)&addr_serv),sizeof(struct sockaddr_in)) <0)

    {

           perror(“bind”);

           exit(1);

    }

    3. 监听本地端口listen()

    1>函数功能:函数listen()用来初始化服务器可连接队列,服务器处理客户端连接请求的时候是顺序处理的,同一时间仅能处理一个客户端连接。当多个客户端的连接请求同时到来的时候,服务器并不是同时处理,而是将不能处理的客户端连接请求放到等待队列中,这个队列的长度由listen()函数来定义。

    2>函数原型:

    #includ<sys/socket.h>

    int listen(int sockfd,int backlog);

    3>形参

    Ø  sockfd: sockfd是调用socket函数返回的文件描述符

    Ø  backlog:指定该连接队列的最大长度。如果连接队列已经达到最大,之后的连接请求被服务器拒绝。大多数系统的设置为20,可以将其设置修改为5或者10,根据系统可承受负载或者应用程序的需求来确定。

    4>返回值:当listen()函数成功运行时,返回值为0;当运行失败时,它的返回值为-1,错误代码存入errno中。

    5>.listen()函数的例子:

    #define SERV_PORT 3000

    int main(int argc,char *argv[])

    {

    int sock_fd;

    struct sockaddr_in addr_serv,addr_client;/*本地的地址信息*/

    sock_fd = socket(AF_INET,SOCK_DGRAM,0);

    if(sock_fd< 0){

           perror(“socket”);

           exit(1);

    }

    memset(&serv_addr,0,sizeof(structsockaddr_in));

    addr_serv.sin_family= AF_INET;/*协议族*/

    addr_serv.sin_port= htons(SERV_PORT);/*本地端口号*/

    addr_serv.sin_addr.s_addr= htonl(INADDR_ANY); /*任意本地地址*/
    /*套接字绑定*/

    if(bind(sock_fd,(structsockaddr *)&addr_serv),sizeof(struct sockaddr_in)) <0)

    {

           perror(“bind”);

           exit(1);

    }

    //设置服务器侦听队列的长度

    if(listen(sock_fd,5) <0){

           perror(“listen”);

           exit(1);

    }

    4. accept(接收一个网络请求)

    1>函数功能:

    当一个客户端的连接请求到达服务器主机侦听的端口时,此时客户端的连接会在队列中等待,知道使用服务器处理接收请求。

    函数accept()成功执行后,会返回一个新的套接口文件描述符来表示客户端的连接,客户端连接的信息可以通过这个新描述符来获得。因此当服务器成功处理客户端的请求连接后,会有两个文件描述符,老的文件描述符表示客户端的连接,函数send()和recv()通过新的文件描述符进行数据收发。

    2>函数原型:

    #include<sys/types.h>

    #include<sys/socket.h>

    int accept(int sock_fd,struct sockaddr*addr,socklen_t *addrlen);

    3>形参

    Ø  sock_fd:是由函数socket创建,经函数bind绑定到本地某一端口上,然后通过函数listen转化而来的监听套接字。

    Ø  addr:用来保存发起连接请求的主机的地址和端口。

    Ø  addrlen是addr 所指向的结构体的大小。

    4>返回值:accept()函数的返回值是新连接的客户端套接字文件描述符,与客户端之间的通信是通过accept()返回的新套接字文件描述符来进行的,而不是通过建立套接字时的文件描述符。如果accept()函数发生错误,accept()会返回-1,通过errno可以得到错误值。

    5>如果参数sock_fd所指定的套接字被设置为阻塞方式(Linux下的默认方式),且连接请求队列为空,则accept()将被阻塞直到有连接请求到此为止;如果参数s所指定的套接字被设置为非阻塞方式,如果队列为空,accept将立即返回-1,errno被设置为EAGAIN.

    6>实例:

    int client_fd;

    int client_len;

    struct sockaddr_in  client_addr;

    client_len = sizeof(struct sockaddr_in);

    client_fd = accept(sock_fd,(struct sockaddr *)&client_addr,&client_len);

    if(conn_fd< 0){

           perror(“accept”);

    exit(1);

    }

    5. connect(连接目标网络服务器)

    1>函数功能:

    客户端在建立套接字之后,不需要进行地址绑定,就可以直接连接服务器。连接服务器的函数为connect(),此函数连接指定参数的服务器,例如IP地址,端口号。

    如果是TCP编程,则connect()函数用于服务器发出连接请求,服务器的IP地址和端口号由 参数serv_addr指定。

    如果是UDP编程,则connect函数并不建立真正的连接,它只是告诉内核与该套接字进行通信的目的地址(由第二个参数指定),只有该目的地址发来的数据才会被该socket接收。调用connect函数的好处是不必在每次发送和接收数据时都指定目的地址。

    2>函数原型:

    #include<sys/types.h>

    #include<sys/socket.h>

    int connect(int sock_fd,struct sockaddr  *serv_addr,socklen_taddrlen);

    3>形参:

    Ø  sock_fd:建立套接字时返回的套接字文件描述符,调用socket()返回的。

    Ø  serv_addr:是一个指向数据结构sockaddr的指针,其中包括客户端需要连接的服务器的目的IP地址和端口号。

    Ø  addrlen:表示了第二了参数的大小,可以使用sizeof(struct sockaddr)

    4>执行成功后返回0,有错误发生则返回-1,错误代码存入errno中。

    5>实例:

    int sock_fd;

    struct sockaddr_in serv_addr;
    if(-1 == (sock_fd == socket(AF_INET,SOCK_STREAM,0))){

                  printf(“Error: Unable to createsocket(%i)…\n”,errno);

                  perror(“sockets”);

                  exit(1);

    }

    memset(&serv_addr,0,sizeof(structsockaddr_in));

    serv_addr.sin_family= AF_INET;

    serv_addr.sin_port= htons(DEST_PORT);

    serv_addr.sin_addr.s_addr= inet(DEST_IP_ADDRESS);

    if(-1== connect(sock_fd,(struct sockaddr *)&serv_add,sizeof(struct sockaddr))){

           printf(“Error:unable to the establishconnection to socket(%i)…\n”,errno);

           perror(“socks”);

           close(sock_fd);

           exit(1);

    }

    6. send(发送数据)

    1>函数功能:函数send用来在TCP套接字上发送数据,send只能对处于连接状态的套接字使用。

    2>函数原型

    #include<sys/types.h>

    #include<sys/socket.h>

    ssize_t send(int conn_fd,const void *msg,size_t len, int flags);

    3>函数形参:

    Ø  conn_fd:为已建立好连接的套接字描述符,即调用accept()函数后返回的套接字描述符。

    Ø  msg:存放发送数据的缓冲区。

    Ø  len:发送缓冲区的长度

    Ø  flags:为控制选项,一般设置为0,或取以下值:

    ²  MSG_OOB:在指定的套接字上发送带外数据(out-of-band data),该类型的套接字必须支持带外数据(如:SOCK_STREAM).

    ²  MSG_DONTROUTE:通过最直接的路径发送数据,而忽略下层协议的路由设置。

    4>返回值:

    执行成功返回实际发送数据的字节数,出错则返回-1,错误代码存入errno中。

    执行成功只是说明数据写入套接字的缓冲区中,并不表示数据已经成功地通过网络发送到目的地。

    5>实例:

    #define  BUFFERSIZE  1500

    char  send_buf[BUFFERSIZE];

    ……

    if(send(conn_fd,send_buf,len,0)< 0){

           perror(“send”);

    exit(1);

    7. recv(接收数据)

    1>函数功能:recv()用来TCP套接字上接收数据。函数recv从指定的套接字描述符上接收数据并保存到指定buf中。

    2>函数原型

    #include<sys/types.h>

    #include<sys/socket.h>

    ssize_t recv(int conn_fd,void *buf,size_t len,int flags);

    3>函数形参:

    Ø  conn_fd: 为已建立好连接的套接字描述符,即调用accept()函数后返回的套接字描述符

    Ø  buf:接收缓冲区

    Ø  len:接收缓冲区的大小

    Ø  flags:为控制选项,一般设置为0或取以下数值

    ²  MSG_OOB:请求接收带外数据

    ²  MSG_PEEK:只查看数据而不读出

    ²  MSG_WAITALL:只在接收缓冲区满时才返回。

    4>函数返回值

    函数执行成功返回接收到的数据字节数,出错返回-1,错误代码存入errno中。

    5>实例:

    #define  BUFFERSIZE  1500

    char recv_buf[BUFFERSIZE];

    ……

    if(recv(conn_fd,recv_buf,sizeof(recv_buf),0)< 0){

           perror(“recv”);

    exit(1);

    8. close

    1>函数原型:

    int  close(int fd);

    2>函数功能:

    函数close用来关闭一个套接字描述符。

    3>函数形参:

    Ø  参数fd为一个套接字描述符。

    4>返回值:

    执行成功返回0,出错则返回-1.错误代码存入errno中。

    说明:close()函数的头文件是#include<unistd.h>.

    三.基于Linux的TCP套接字编程实例

    1.实例程序分为服务器端和客户端,客户端把Hello tigerjibo发送给服务器端;服务器端接收到字符串后,发送接收到的总字符串个数给客户端;

    2.服务器端程序:



      1 #include<stdio.h>
      2 #include<stdlib.h>
      3 #include<string.h>
      4 #include<errno.h>
      5 
      6 
      7 #include<sys/types.h>
      8 #include<sys/socket.h>
      9 #include<unistd.h>//close()
     10 #include<netinet/in.h>//struct sockaddr_in
     11 #include<arpa/inet.h>//inet_ntoa
     12 #define  QUEUE_LINE  12
     13 #define  SOURCE_PORT 8000
     14 
     15 #define  SOURCE_IP_ADDRESS "192.168.1.6"
     16 
     17 void process_info(int s)
     18 {
     19         int recv_num;
     20         int send_num;
     21         char recv_buf[50];
     22         char send_buf[50];
     23         while(1){
     24                 printf("begin recv:\n");
     25                 recv_num = recv(s,recv_buf,sizeof(recv_buf),0);
     26                 if(recv_num <0){
     27                         perror("recv");
     28                         exit(1);
     29                 } else {
     30                         recv_buf[recv_num] = '\0';
     31                         printf("recv sucessful:%s\n",recv_buf);
     32                 }
     33                 sprintf(send_buf,"recv %d numbers bytes\n",recv_num);
     34                 printf("begin send\n");
     35                 send_num = send(s,send_buf,sizeof(send_buf),0);
     36                 if (send_num < 0){
     37                         perror("sned");
     38                         exit(1);
     39                 } else {
     40                         printf("send sucess\n");
     41                 }
     42         }
     43 }
     44 int main()
     45 {
     46         int sock_fd,conn_fd;
     47         int client_len;
     48         pid_t pid;
     49         struct sockaddr_in addr_serv,addr_client;
     50         sock_fd = socket(AF_INET,SOCK_STREAM,0);
     51         if(sock_fd < 0){
     52                 perror("socket");
     53                 exit(1);
     54         } else {
     55                 printf("sock sucessful\n");
     56         }
     57         //初始化服务器端地址
     58         memset(&addr_serv,0,sizeof(addr_serv));
     59         addr_serv.sin_family = AF_INET;
     60         addr_serv.sin_port = htons(SOURCE_PORT);
     61         addr_serv.sin_addr.s_addr =inet_addr(SOURCE_IP_ADDRESS);
     62         client_len = sizeof(struct sockaddr_in);
     63         if(bind(sock_fd,(struct sockaddr *)&addr_serv,sizeof(struct sockaddr_in))<0){
     64                 perror("bind");
     65                 exit(1);
     66         } else {
     67                 printf("bind sucess\n");
     68         }
     69         if (listen(sock_fd,QUEUE_LINE) < 0){
     70                 perror("listen");
     71                 exit(1);
     72         } else {
     73                 printf("listen sucessful\n");
     74         }
     75         while(1){
     76                  printf("begin accept:\n");
     77                  conn_fd = accept(sock_fd,(struct sockaddr *)&addr_client,&client_len);
     78                  if(conn_fd < 0){
     79                         perror("accept");
     80                         exit(1);
     81                  }
     82                  printf("accept a new client,ip:%s\n",inet_ntoa(addr_client.sin_addr));
     83                  pid = fork();
     84                  if(0 == pid){         //子进程
     85                         close(sock_fd);//在子进程中关闭服务器的侦听
     86                         process_info(conn_fd);//处理信息
     87                  } else {
     88                         close(conn_fd);//在父进程中关闭客户端的连接
     89                  }
     90         }
     91 
     92 }

     3.客户端程序:


      1 #include<stdio.h>
      2 #include<string.h>
      3 #include<stdlib.h>
      4 #include<errno.h>
      5 
      6 #include<sys/types.h>
      7 #include<sys/socket.h>
      8 #include<unistd.h>//close()
      9 #include<netinet/in.h>//struct sockaddr_in
     10 #include<arpa/inet.h>//inet_ntoa
     11 
     12 #define DEST_PORT 8000
     13 #define DEST_IP_ADDRESS "192.168.1.6"
     14 
     15 /*客户端的处理过程*/
     16 void process_info(int s)
     17 {
     18         int send_num;
     19         int recv_num;
     20         char send_buf[]="tigerjibo";
     21         char recv_buf[50];
     22         while(1){
     23                 printf("begin send\n");
     24                 send_num = send(s,send_buf,sizeof(send_buf),0);
     25                 if (send_num < 0){
     26                         perror("send");
     27                         exit(1);
     28                 } else {
     29                         printf("send sucess:%s\n",send_buf);
     30                 }
     31                 printf("begin recv:\n");
     32                 recv_num = recv(s,recv_buf,sizeof(recv_buf),0);
     33                 if(recv_num < 0){
     34                         perror("recv");
     35                         exit(1);
     36                 } else {
     37                         recv_buf[recv_num]='\0';
     38                         printf("recv sucess:%s\n",recv_buf);
     39                 }
     40         }
     41 }
     42 int main(int argc,char *argv[])
     43 {
     44         int sock_fd;
     45         struct sockaddr_in addr_serv;//服务器端地址
     46 
     47         sock_fd = socket(AF_INET,SOCK_STREAM,0);
     48         if(sock_fd < 0){
     49                 perror("sock");
     50                 exit(1);
     51         } else {
     52                 printf("sock sucessful:\n");
     53         }
     54         memset(&addr_serv,0,sizeof(addr_serv));
     55         addr_serv.sin_family = AF_INET;
     56         addr_serv.sin_port =  htons(DEST_PORT);
     57         addr_serv.sin_addr.s_addr = inet_addr(DEST_IP_ADDRESS);
     58        if( connect(sock_fd,(struct sockaddr *)&addr_serv,sizeof(struct sockaddr)) < 0){
     59                 perror("connect");
     60                 printf("connect (%d)\n",errno);
     61                 exit(1);
     62        } else {
     63                 printf("connect sucessful\n");
     64        }
     65         process_info(sock_fd);
     66         close(sock_fd);
     67 }
    展开全文
  • TCP网络编程处理的三个半事件

    千次阅读 2018-11-15 09:52:54
    TCP网络编程最本质的是处理三个半事件: 连接建立:包括服务器端被动接受连接(accept)和客户端主动发起连接(connect)。TCP连接一旦建立,客户端和服务端就是平等的,可以各自收发数据。 连接断开:包括主动...
  • TCP网络编程之echo回射程序

    千次阅读 2017-12-06 16:01:03
    TCP网络编程有三个例子最值得学习研究,分别是echo、chat、proxy,都是长连接协议。接下来,把这几个例子都实现。本节用一个简单的例子来讲TCP客户/服务器程序框架,这也是echo的实现。 程序的基本流程: 客户从...
  • Qt的Tcp网络编程

    千次阅读 2013-03-02 20:00:23
     使用Qt 封装的socket接口进行tcp网络编程。在Qt中客户端使用QTcpSocket,服务器端使用QTcpServer。服务器端在相应的端口进行监听,一旦发现客户端的连接请求,就会发出newConnect()信号。通过关联这个信号,在槽...
  • 利用go的tcp网络编程Api实现一个简单的http服务器,直接上代码(涉及的概念较多) package main import ( &amp;amp;amp;quot;fmt&amp;amp;amp;quot; &amp;amp;amp;quot;net&amp;amp;amp;quot; ...
  • QT TCP网络编程

    万次阅读 多人点赞 2017-03-22 20:36:45
    首先介绍一下TCP:(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。相比而言UDP,就是开放式、无连接、不可靠的传输层通信协议。 下面,我一次进行客户端和...
  • 本文主要讲解C/S模型,对服务器端和客户端的流程和函数的使用进行解析,以及网络编程中对信号的处理...TCP网络编程中常用的函数主要有:socket(),bind(),listen(),accept(),read(),write(),connect(),close();服务器端
  • TCP介绍及TCP网络编程

    千次阅读 2017-11-12 00:05:50
    一、TCP头部结构: ①16位端口号及16位目的端口号:告知主机该报文段来自哪里(源端口)要传给那个上层协议或应用程序(目的端口)。 ②32位序号:一次TCP通信过程中某一个传输方向上的字节流的每个字节的编号。...
  • 一、Linux下TCP网络编程基础,需要了解相关函数 Socket():用于套接字初始化。 Bind():将 socket 与本机上的一个端口绑定,就可以在该端口监听服务请求。 Listen():使socket处于被动的监听模式,并为该 socket ...
  • **TCP网络编程 聊天室(群聊与私聊)完整代码实现实现工具:Socket、多线程、IO流实现效果图Client.javapackage com.maple.tcp;import java.io.BufferedReader; import java.io.IOException; import java.io....

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 37,361
精华内容 14,944
关键字:

tcp网络编程