Linux高级编程--10.Socket编程

Linux下的Socket编程大体上包括Tcp Socket、Udp Socket即Raw Socket这三种,其中TCP和UDP方式的Socket编程用于编写应用层的socket程序,是我们用得比较多的,而Raw Socket则用得相对较少,不在本文介绍范围之列。

TCP Socket

基于TCP协议的客户端/服务器程序的一般流程一般如下:

它基本上可以分为三个部分:

一、建立连接:

  • 服务器调用socket()、bind()、listen()完成初始化后,调用accept()阻塞等待,处于监听端口的状态
  • 客户端调用socket()初始化后,调用connect()发出SYN段并阻塞等待服务器应答
  • 服务器应答一个SYN-ACK段,客户端收到后从connect()返回,同时应答一个ACK段,服务器收到后从accept()返回。

二、传输数据:

建立连接后,TCP协议提供全双工的通信管道,服务器端和客户端根据协议可以通过read和write的反复调用实现数据的传输

三、关闭连接:

当数据传输已经完成后,服务器和客户端可以调用Close关闭连接,一端关闭连接后,另一端read函数则会返回0,可以根据这个特征来感应另一端的退出。

下面就以一个简单的EchoServer演示一下如何创建服务器端和客户端代码,其中和socket相关api都会高亮显示。

服务器端示例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define MAXLINE 80
#define SERV_PORT 8000

int main(void)
{
    char buf[MAXLINE];

    int listenfd = 0;
    listenfd = socket(AF_INET, SOCK_STREAM, 0);

    sockaddr_in servaddr = {0};
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(SERV_PORT);

    bind(listenfd, (sockaddr *)&servaddr, sizeof(servaddr));
    listen(listenfd, 20);

    printf("Accepting connections ...\n");
    while (1)
    {
        sockaddr_in cliaddr = {0};
        socklen_t cliaddr_len = sizeof(cliaddr);
        int connfd = accept(listenfd, (sockaddr *)&cliaddr, &cliaddr_len);

        char str[INET_ADDRSTRLEN];
        printf("connected from %s at PORT %d\n",
                inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
                ntohs(cliaddr.sin_port));

        while(true)
        {
            int count = read(connfd, buf, MAXLINE);
            if (count == 0)
                break;

            write(connfd, buf, count);
        }

        close(connfd);
        printf("closed from %s at PORT %d\n",
                inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
                ntohs(cliaddr.sin_port));
    }
}

PS:这里需要注意的一下的是sock函数的第二个参数SOCK_STREAM,它表示是一个TCP连接,后面我们会介绍通过传入SOCK_DGRAM打开udp连接。

服务器端主体流程就是一个死循环,它接受一个socket连接,然后将其原封不动的返回给客户端,待客户端退出后,关闭socket连接,再次接受下一个socket连接。

客户端代码如下:

#include <stdio.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define MAXLINE 80
#define SERV_PORT 8000
#define MESSAGE "hello world"

int main(int argc, char *argv[])
{
    char buf[MAXLINE];

    int sockfd = socket(AF_INET, SOCK_STREAM, 0);

    sockaddr_in servaddr = {0};
    servaddr.sin_family = AF_INET;
    inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
    servaddr.sin_port = htons(SERV_PORT);

    if (0 != connect(sockfd, (sockaddr *)&servaddr, sizeof(servaddr)))
    {
        printf("connected failed");
        return 1;
    }

    write(sockfd, MESSAGE, sizeof(MESSAGE));
    int count = read(sockfd, buf, MAXLINE);

    printf("Response from server: %s\n",buf);

    close(sockfd);
    return 0;
}

UDP Socket

典型的UDP客户端/服务器通讯过程如下图所示:

由于UDP不需要维护连接,程序逻辑简单了很多,但是UDP协议是不可靠的,实际上有很多保证通讯可靠性的机制需要在应用层实现,可能反而会需要更多代码。

典型的示例如下:

/* server.cpp */
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define MAXLINE 80
#define SERV_PORT 8000

int main(void)
{
    char buf[MAXLINE];
    char str[INET_ADDRSTRLEN];

    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    sockaddr_in servaddr = {0};
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(SERV_PORT);

    bind(sockfd, (sockaddr *)&servaddr, sizeof(servaddr));

    printf("Accepting connections ...\n");
    while (1)
    {
        sockaddr_in cliaddr;
        socklen_t cliaddr_len = sizeof(cliaddr);

        int count = recvfrom(sockfd, buf, MAXLINE, 0, (sockaddr *)&cliaddr, &cliaddr_len);
        if (count < 0)
        {
            printf("recvfrom error");
            continue;
        }

        printf("received from %s at PORT %d\n",
             inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
             ntohs(cliaddr.sin_port));

        sendto(sockfd, buf, count, 0, (sockaddr *)&cliaddr, sizeof(cliaddr));
    }
}

/* client.cpp */
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define MAXLINE 80
#define SERV_PORT 8000

int main(int argc, char *argv[])
{
    char buf[MAXLINE];
    char str[INET_ADDRSTRLEN];

    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    sockaddr_in servaddr = {0};
    servaddr.sin_family = AF_INET;
    inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
    servaddr.sin_port = htons(SERV_PORT);

    while (fgets(buf, MAXLINE, stdin) != NULL)
    {
        int count = sendto(sockfd, buf, strlen(buf), 0, (sockaddr *)&servaddr, sizeof(servaddr));
        if (count == -1)
        {
            printf("sendto error");
            return 0;
        }

        count = recvfrom(sockfd, buf, MAXLINE, 0, NULL, 0);
        if (count == -1)
        {
            printf("recvfrom error");
            return 0;
        }

        write(STDOUT_FILENO, buf, count);
    }

    close(sockfd);
    return 0;
}

来自为知笔记(Wiz)

时间: 2024-08-27 16:21:38

Linux高级编程--10.Socket编程的相关文章

多线程编程以及socket编程_Linux程序设计4chapter15

看了Linux程序设计4中文版,学习了多线程编程和socket编程.本文的程序参考自Linux程序设计4的第15章. 设计了一个客户端程序,一个服务端程序.使用TCP协议进行数据传输. 客户端进程创建了一个客户端使用的socket,一个socket地址结构体.设置这个socket地址结构体的端口和地址为要连接的服务端的端口和ip.然后使用客户端的socket尝试连接服务端(connect),如果连接失败直接退出.如果连接成功,则使用这个连接成功的socket进行数据传输(send和recv).首

【Linux编程】socket编程

套接字是通信端点的抽象.文件描写叙述符用open函数创建,而套接字描写叙述符用socket函数创建.socket函数原型例如以下: int socket(int domain, int type, int protocol); // 返回值:成功返回套接字描写叙述符,失败返回-1 domain域确定通信特性.不同的域表示地址的格式不同,表示域的常数以AF开头.表示地址族(address family): watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvb

网络协议 10 - Socket 编程:实践是检验真理的唯一标准

系列文章传送门: 网络协议 1 - 概述 网络协议 2 - IP 是怎么来,又是怎么没的? 网络协议 3 - 从物理层到 MAC 层 网络协议 4 - 交换机与 VLAN:办公室太复杂,我要回学校 网络协议 5 - ICMP 与 ping:投石问路的侦察兵 网络协议 6 - 路由协议:敢问路在何方? 网络协议 7 - UDP 协议:性善碰到城会玩 网络协议 8 - TCP 协议(上):性恶就要套路深 网络协议 9 - TCP协议(下):聪明反被聪明误 ????前面一直在说各种协议,偏理论方面的知

1.socket编程:socket编程,网络字节序,函数介绍,IP地址转换函数,sockaddr数据结构,网络套接字函数,socket相关函数,TCP server和client

 1  Socket编程 socket这个词可以表示很多概念: 在TCP/IP协议中,"IP地址+TCP或UDP端口号"唯一标识网络通讯中的一个进程,"IP 地址+端口号"就称为socket. 在TCP协议中,建立连接的两个进程各自有一个socket来标识,那么这两个socket组成的socket pair就唯一标识一个连接.socket本身有"插座"的意思,因此用来描述网络连 接的一对一关系. TCP/IP协议最早在BSD UNIX上实现,

六、网络编程(socket编程)

一.客户端/服务器架构 1.硬件C/S架构(打印机) 2.软件C/S架构 互联网处处是C/S架构 比如百度网站是服务端,浏览器是客户端(B/S架构也是C/S架构的一种) 腾讯作为服务端提供微信服务,需要下载微信安装包安装使用才可以去聊微信. C/S架构与socket的关系: 用socket就是为了完成C/S架构的开发 server端(必须遵守的): 1.位置必须固定死,绑定一个固定的地址 2.对外一直提供服务,稳定运行 3.支持并发(让多个客户端感觉是同时被服务着) 二.OSI七层 1.引子 须

Python学习笔记——基础篇【第七周】———FTP作业(面向对象编程进阶 &amp; Socket编程基础)

FTP作业 本节内容: 面向对象高级语法部分 Socket开发基础 作业:开发一个支持多用户在线的FTP程序 面向对象高级语法部分 参考:http://www.cnblogs.com/wupeiqi/p/4766801.html metaclass 详解文章:http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python 得票最高那个答案写的非常好 Socket 编程 参考:http://www.cnblogs.co

02-【IOS网络编程】socket编程 - Asyncsocket

socket编程Asyncsocket iPhone的标准推荐是CFNetwork 库编程,其封装好的开源库是 cocoa AsyncSocket库,用它来简化CFNetwork的调用,它提供了异步操作 主要特性有: 队列的非阻塞的读和写,而且可选超时.你可以调用它读取和写入,它会当完成后告知你 自动的socket接收.如果你调用它接收连接,它将为每个连接启动新的实例,当然,也可以立即关闭这些连接 委托(delegate)支持.错误.连接.接收.完整的读取.完整的写入.进度以及断开连接,都可以通

iOS网络编程笔记——Socket编程

一.什么是Socket通信: Socket是网络上的两个程序,通过一个双向的通信连接,实现数据的交换.这个双向连路的一端称为socket.socket通常用来实现客户方和服务方的连接.socket是TCP/IP协议的一个十分流行的编程接口.一个socket由一个IP地址和一个端口号唯一确定.TCP/IP协议的传输层又有两种协议:TCP(传输控制协议)和UDP(用户数据报协议).TCP是基于连接的,而UDP是无连接的:TCP对系统资源的要求较多,而UDP少:TCP保证数据的正确性而UDP可能丢包:

tcp编程、socket编程

tcp编程(需要建立连接,三次握手,四次挥手,然后发送信息流,数据包是有序的) udp编程(知道IP.端口直接发送数据,数据包可能是无序的) 1.客户端和服务器客 socket编程 1.服务端的处理流程 a.监听端口 b.接收客户端的链接 c.创建goroutine,处理该链接 2.客户端的处理流程 a.建立与服务端的链接 b.进行数据收发 c.关闭链接 3.服务端代码 package main import ( "fmt" "net"//导入socket的包 )