一个简单的hello/hi的网络聊天程序

TCP套接字函数了解

socket函数

    为了执行网络I/O,一个进程必须做的第一件事情就是调用socket函数,指定期望的通信协议类型(使用ipv4的TCP、使用ipv6的UDP、Unix域字节流协议等)

#include<sys/socket.h>
int socket(int family, int type, int protocol);
                    返回:若成功则为非负描述符
                         若出错则为-1

    其中family参数指明协议族,type参数之梦套接字类型,protocol参数为某个协议类型常值,或者为0,以选择所给定family和type组合的系统默认值

family 说明
AF_INET Ipv4协议
AF_INET6 IPv6协议
AF_LOCAL Unix域协议
AF_ROUTE 路由套接字
AF_KEY 密钥套接字

**socket函数的family常值**

   type           说明   

SOCK_STREAM 字节流套接字
SOCK_DGRAM 数据包套接字
SOCK_SEQPACKET 有序分组套接字
SOCK_RAW 原始套接字

**socket函数的type常值**

protocol       说明   

IPPROTO_TCP TCP传输协议
IPPROTO_UDP UDP传输协议
IPPROTO_SCTP SCTP传输协议

**socket函数AF_INET或FF_INET6的protoco常值**

    socket函数在成功时返回一个小的非负整数值,它与文件描述符相似,我们把它称为套接字描述符(socket description),简称sockfd。为了得到整个套接字描述符,我们只是指定了协议族(ipv4、ipv6或unix)和套接字类型(字节流、数据报或原始套接字)

connect函数

TCP客户用connect函数来建立与TCP服务器的连接

#include<sys/socket.h>
int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen)
                返回:若成功则为0
                     若出错则为-1

    sockfd是由socket函数返回的套接字描述符,第二个、第三个参数分别是指向套接字地址结构的指针和该结构的大小。套接字地址必须含有服务器的IP地址和口号。

    客户在调用connect函数之前不必非得调用bind函数,因为需要的话,内核会确定源IP地址,并选择一个临时端口作为源端口。

bind函数

    bind函数把一个本地协议地址赋予一个套接字。对于网际网协议,协议地址是32位的ipv4地址或128位的ipv6地址与16位的TCP或UDP端口号的组合。

#include<sys/socket.h>
int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen)
                        返回:若成功则为0
                             若出错则为-1

    第二个参数是一个指向特定于协议的地址结构的指针,第三个参数是该地址结构的长度。对于TCP,调用bind函数可以指定一个端口号,或指定一个ip地址,也可以两者都指定,还可以都不指定。

listen函数

    listen函数仅由TCP服务器调用,它做两件事
  • 当socket函数创建一个套接字时,它被假设为一个主动套接字,也就是说,它是将调用connect发起连接的客户套接字。listen函数把一个未连接的套接字转换为一个被动套接字,指示内核应接受指向该套接字的连接请求。根据TCP连接转换图,调用listen导致套接字从CLOSED转台转换为LISTEN状态。
  • 本函数的第二个参数规定了内核应该为相应套接字排队的最大连接个数、

    #include<sys/socket.h>
    int listen(int sockfd, int backlog)
    返回:若成功则为0
    若出错则为-1

      本函数通常应该在调用socket和bind两个函数之后,并在调用accept函数之前调用。为了更加理解backlog参数,我们必须认识到内核为任何一个给定的监听套接字维护两个队列
  • 未完成连接队列(incomplete Connection queue),每个这样的SYN分节对应其中一项:已由某个客户发出并到达服务器,而服务器正在等待完成相应的TCP三次握手过程
  • 已完成连接队列(completed Connection queue),每个已完成TCP三次握手过程的客户对应其中一项

accept函数

    accept函数由TCP 服务器调用,用于从已完成连接队列对头返回下一个已完成连接。如果已完成连接队列为空,那么进程被投入到睡眠。

#include<sys/socket.h>
int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen)
                    返回:若成功为为非负描述符
                         若出错则为-1

    参数cliaddr和addrlen用来返回已连接的对端进程(客户)的协议地址。addrlen是值-结果参数:调用前,将由*addrlen所引用的整数值置为有cliaddr所指的套接字地址结构的长度,返回时,该整数值即为由内核存放在该套接字地址结构中的确切字节数。

    如果accept函数返回成功,那么返回值是由内核自动生成的一个全新描述符,代表与所返回的TCP连接。其第一个参数为监听套接字(listening socket)描述符(由socket创建,随后用作bind和listen的第一个参数的描述符),它的返回值为已连接套接字(connected socket)描述符。

    区分监听套接字(listening socket)描述符和已连接套接字(connected socket)描述符:
  • 一个服务器通常仅仅是创建一个监听套接字,他在该服务器的声明周期内一直存在。
  • 内核为每个服由务器进程接受的客户连接创建一个已连接套接字(说明TCP三次握手已经完成)。当服务器完成对某个给定客户机的服务时,相应的已连接套接字就被关闭

close函数

    通常的unix close 函数也用来关闭套接字,并终止TCP连接

#include<unistd.h>
int close(int sockfd);
                    返回:若成功则为0
                         若出错则为-1

    close一个TCP套接字的默认行为是把该套接字标记为已关闭,然后立即返回到调用进程。该套接字描述符不能再由调用进程使用,也就是说它不能再做为read或write的第一个参数,然而TCP将尝试发送已排队等待发送到对端的任何数据,发送完毕后发生的是正常的TCP连接终止序列

下图为基于TCP客户/服务器程序的套接字函数及流程

服务端代码:server.c

//server.cpp
#include< iostream>
#include< winsock2.h>
#include< WS2tcpip.h>
using namespace std;
#pragma comment(lib,"ws2_32.lib")
constexpr auto serverIP = "127.0.0.1";//服务器端的IP地址,这里设为本机回环地址;
constexpr auto serverPort = 6789;//服务器端进程的端口号,值大于1023即可;
int main() {
    //第一步:WinSock初始化
    WORD wVersion = MAKEWORD(2, 2);
    WSADATA wsaData;
    //WSAStartup,Windows Sockets Asynchronous,Windows异步套接字的启动命令。
    if (WSAStartup(wVersion, &wsaData)) {
        cout << "WSAStartup......\n";
        return 0;
    }
    //创建socket
    SOCKET sockServer;
    sockServer = socket(AF_INET, SOCK_STREAM, 0);
    //服务器地址
    SOCKADDR_IN serverAddr, clientAddr;
    serverAddr.sin_family = AF_INET;
    in_addr dst;
    //点分十进制的IPv4地址转换为网络字节的IP(整型)
    int res = inet_pton(AF_INET, serverIP, (void*)&dst);
    //将serverIP地址转换为in_addr的结构体,并复制在dst中
    if (res == 1) {
        serverAddr.sin_addr.S_un.S_addr = dst.s_addr;
    }
    else {
        cout << "The address is error." << endl;
    }
    serverAddr.sin_port = htons(serverPort);//host to network short
                                            //绑定
    bind(sockServer, (SOCKADDR*)&serverAddr, sizeof(SOCKADDR));
    //监听
    listen(sockServer, 10);//10(服务器最多可以处理的用户数)
                           //处理
    int acceptResult = sizeof(SOCKADDR);
    SOCKET sockAccept;
    cout << "The server is waiting for client's connection request..." << endl;
    sockAccept = accept(sockServer, (SOCKADDR*)&clientAddr, &acceptResult);
    if (sockAccept == INVALID_SOCKET) {
        cout << "The server failed to accept the client's connection request." << endl;
        return 0;
    }
    else {
        cout << "The server accepted the client' connection request." << endl;
    }
    //cout <<clientAddr.sin_addr .S_un.S_addr<< endl;
    //cout << clientAddr.sin_port;
    //传送、接收数据
    char sendbuffer[256] = { '\0' };
    char recivebuffer[256] = { '\0' };
    for (;;) {
        //接收数据
        recv(sockAccept, recivebuffer, 256, 0);
        if (strcmp(recivebuffer, "quit") == 0) {
            cout << "client quit." << endl;
            break;
        }
        else {
            cout << "Client says:>" << recivebuffer << endl;
            cout << "Server says:>";
            cin >> sendbuffer;
            send(sockAccept, sendbuffer, strlen(sendbuffer) + 1, 0);
        }
    }
    closesocket(sockServer);
    WSACleanup();
    return 0;
}

客户端代码:client.c

#include< iostream>
#include< winsock2.h>
#include< ws2tcpip.h>
using namespace std;
#pragma comment(lib,"ws2_32.lib")
constexpr auto serverIP = "127.0.0.1";//服务器端的IP地址;
constexpr auto serverPort = 6789;//服务器端进程的端口号;
int main() {
    //WinSock初始化
    WORD wVersion = MAKEWORD(2, 2);
    WSADATA wsaData;
    //WSAStartup,Windows Sockets Asynchronous,Windows异步套接字的启动命令。
    if (WSAStartup(wVersion, &wsaData)) {
        cout << "WSAStartup......" << endl;
        return 0;
    }
    //创建套接字
    SOCKET sockClient;
    sockClient = socket(AF_INET, SOCK_STREAM, 0);//1.address family,地址族协议,IPv4
                                                 //2.流式套接字
                                                 //3.已使用TCP,默认0
                                                 //服务器地址
    SOCKADDR_IN  serverAddr;
    serverAddr.sin_family = AF_INET;
    in_addr dst;
    //点分十进制的IPv4地址转换为网络字节的IP(整型)
    int IPResult = inet_pton(AF_INET, serverIP, &dst);

    //将serverIP地址转换为in_addr的结构体,并复制在dst中
    if (IPResult == 1) {
        serverAddr.sin_addr.S_un.S_addr = dst.s_addr;
    }
    else {
        cout << "The IP is error." << endl;
    }
    serverAddr.sin_port = htons(serverPort);
    //请求连接
    int connectResult = connect(sockClient, (SOCKADDR*)&serverAddr, sizeof(SOCKADDR));
    if (connectResult != 0) {
        cout << "The client's connection request failed." << endl;
    }
    else {
        cout << "The client's connection request is accepted." << endl;
    }
    //发送及接收数据
    char sendbuffer[256] = { '\0' };
    char receivebuffer[256] = { '\0' };
    for (;;) {
        //发送数据
        cout << "The client says:>";
        cin >> sendbuffer;
        if (strcmp(sendbuffer, "quit") == 0) {
            break;
        }
        else {
            send(sockClient, sendbuffer, strlen(sendbuffer) + 1, 0);
        }
        //接收数据
        recv(sockClient, receivebuffer, 256, 0);
        cout << "The server says:>" << receivebuffer << endl;
    }
    closesocket(sockClient);//关闭套接字
    WSACleanup();//注销及释放分配资源
    return 0;
}

运行截图

原文地址:https://www.cnblogs.com/kttme/p/12024890.html

时间: 2024-10-07 12:29:26

一个简单的hello/hi的网络聊天程序的相关文章

一个hello/hi的简单的网络聊天程序

我选择使用python来实现hello/hi的简单网络聊天程序,源代码包括两个部分,客户端代码和服务器端代码,源代码部分如下图所示: 服务器端代码 1 import socket 2 3 HOST = '127.0.0.1' 4 PORT = 8888 5 6 server = socket.socket() 7 server.bind((HOST, PORT)) 8 server.listen(1) 9 10 print(f'the server is listening at {HOST}:

基于Python完成一个hello/hi的简单的网络聊天程序

一.Socket 套接字简介 套接字(socket)是一个抽象层,应用程序可以通过它发送或接收数据,可对其进行像对文件一样的打开.读写和关闭等操作.套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信.网络套接字是IP地址与端口的组合. 传输层实现端到端的通信,因此,每一个传输层连接有两个端点.那么,传输层连接的端点是什么呢?不是主机,不是主机的IP地址,不是应用进程,也不是传输层的协议端口.传输层连接的端点叫做套接字(socket).根据RFC793的定义:端口号拼接到IP

以您熟悉的编程语言为例完成一个hello/hi的简单的网络聊天程序

在这片博文我们将使用python完成一个hello/hi的简单的网络聊天程序 先做一下准备工作 1.linux的socket基础api: 使用socket()创建套接字 int socket(int af, int type, int protocol); af为IP地址类型,AF_INE和AF_INET6分别对应ipv4和ipv6地址type是数据传输方式,Sock_stream(面向连接套接字)和sock_dgram(无连接套接字)protocol是传输协议,IPPROTO_TCP和IPPR

一个hello/hi的简单的网络聊天程序和python Socket API与Linux Socket API之间的关系

1.Socket概述 套接字(socket)是一个抽象层,应用程序可以通过它发送或接收数据,可对其进行像对文件一样的打开.读写和关闭等操作.套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信.网络套接字是IP地址与端口的组合. 套接字可以看成是两个网络应用程序进行通信时,各自通信连接中的一个端点.通信时,其中的一个网络应用程序将要传输的一段信息写入它所在主机的Socket中,该Socket通过网络接口卡的传输介质将这段信息发送给另一台主机的Socket中,使这段信息能传送到

java实现hello/hi的简单的网络聊天程序与ServerSocket调用栈跟踪

java实现hello/hi的简单的网络聊天程序 网络聊天采用TCP协议通过java实现 import java.io.*; import java.net.Socket; public class Client { public static void main(String[] args) throws Exception{ Socket socket = new Socket("192.168.31.68", 6666); BufferedReader reader = new

在windows环境下用C++完成一个hello/hi网络聊天程序

经过网络程序设计课程的学习,我们了解了socket网络程序编程,接下来,就要学以致用,完成一个hello/hi的网络聊天程序. Socket介绍  Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部. Socket起源于Unix,而Unix/Linux 基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/re

基于Java实现hello/hi简单网络聊天程序

目录 Socket简要阐述 Socket的概念 Socket原理 hello/hi的简单网络聊天程序实现 服务器端 客户端 程序执行结果 跟踪分析调用栈 & Linux API对比 创建ServerSocket 调用栈图示 源码分析 Socket绑定 调用栈图示 源码分析 Socket监听 调用栈图示 源码分析 Socket Accept 调用栈图示 源码分析 Java Socekt API与Linux Socket API 参考链接 Socket简要阐述 Socket的概念 Socket的英文

ubuntu系统下使用python3实现简单的网络聊天程序

这是我的第二篇博客,很遗憾第一篇博客没有得到应有的认可. 可能是因为原理介绍和实操部分不够多,只是单纯分析了某一条指令在打开网页过程中,输出的变化. 在我的第二篇博客中把相关原理介绍的更加详细了,同时丰富了程序代码部分的介绍. 本文对通信相关知识点(如socket套接字.TCP/IP.HTTP通信协议).hello/hi网络聊天程序代码.python socke接口与Linux socket api之间的关系三个方面做了相关介绍 一.网络通信相关知识 首先必须明确一点,我们进行网络通信之前,必须

通过基于java实现的网络聊天程序分析java中网络API和Linux Socket API关系

1. 引言 socket网络编程,可以指定不同的通信协议,在这里,我们使用TCP协议实现基于java的C/S模式下“hello/hi”网络聊天程序 2. 目标 1). 通过该网络聊天程序,了解java Socket API接口的基本用法 2). java Socket API简要介绍 3). linux socket API 简单分析 4). tcp协议的连接和终止 5). 探究java socket API 和 linux socket api之间的关系 3. linux socket API