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

TCP Socket

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

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

一、建立连接:

  1. 服务器调用socket()、bind()、listen()完成初始化后,调用accept()阻塞等待,处于监听端口的状态
  2. 客户端调用socket()初始化后,调用connect()发出SYN段并阻塞等待服务器应答
  3. 服务器应答一个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;
    }

linux系统socket通信编程1的更多相关文章

  1. linux系统socket通信编程详解函数

    linux socket编程之TCP与UDP   TCP与UDP区别 TCP---传输控制协议,提供的是面向连接.可靠的字节流服务.当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之 ...

  2. linux系统socket通信编程实践

    简单介绍并实现了基于UDP(TCP)的windows(UNIX下流程基本一致)下的服务端和客户端的程序,本文继续探讨关于UDP编程的一些细节. 下图是一个简单的UDP客户/服务器模型: 我在这里也实现 ...

  3. linux系统socket通信编程2

    一.概述 TCP(传输控制协议)和UDP(用户数据报协议是网络体系结构TCP/IP模型中传输层一层中的两个不同的通信协议. TCP:传输控制协议,一种面向连接的协议,给用户进程提供可靠的全双工的字节流 ...

  4. Linux 下socket通信终极指南(附TCP、UDP完整代码)

    linux下用socket通信,有TCP.UDP两种协议,网上的很多教程把两个混在了一起,或者只讲其中一种.现在我把自己这两天研究的成果汇总下来,写了一个完整的,适合初学者参考,也方便自己以后查阅. ...

  5. 【Linux教程】Linux系统零基础编程入门,想当大神?这些你都要学

    ✍ 文件和文件系统 文件是Linux系统中最重要的抽象,大多数情况下你可以把linux系统中的任何东西都理解为文件,很多的交互操作其实都是通过文件的读写来实现的. 文件描述符 在Linux内核中,文件 ...

  6. 【转】C# Socket通信编程

    https://www.cnblogs.com/dotnet261010/p/6211900.html#undefined 一:什么是SOCKET socket的英文原义是“孔”或“插座”.作为进程通 ...

  7. linux系统UDP的socket通信编程3

    我刚开始接触linux下的socket编程,边抄边理解udp socket编程,我的疑问是server不指定IP地址,client的目标IP地址是127.0.0.1,这样就可以通信吗?在同一主机下是不 ...

  8. linux系统UDP的socket通信编程2

    UDP套接字编程范例: server端代码如下: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 2 ...

  9. linux系统UDP的socket通信编程

    发送方: /* * File: main.c * Author: tianshuai * * Created on 2011年11月29日, 下午10:34 * * 主要实现:发送20个文本消息,然后 ...

随机推荐

  1. Accumulator

    Accumulator简介 Accumulator是spark提供的累加器,顾名思义,该变量只能够增加. 只有driver能获取到Accumulator的值(使用value方法),Task只能对其做增 ...

  2. 【WPF】设置TextBox内容为空时的提示文字

    <TextBox Width="150" Margin="5"> <TextBox.Resources> <VisualBrush ...

  3. Ubuntu下安装Apache

    Ubuntu为我们提供了 su apt-get install 命令,通过它你可以很方便地安装一些软件,这些软件是放在Ubuntu放置在各个地方的服务器上面,如果你想安装的软件是比较常见的,一般都可以 ...

  4. Android——用对话框做登陆界面(自定义对话框AlertDialog,多线程,进度条ProgressDialog,ListView,GridView,SharedPreferences存,读数据,存取文本,assets文件)

    效果: 1.点击图标进入页面二 2.页面2图片暂停显示5秒进入页面三 3.点击页面三登陆按钮,打开登陆对话框,输入密码进入页面四 点击下载按钮,显示水平进度条 点击保存和获取用户名和密码 进入页面六  ...

  5. BloomFilter——大规模数据处理利器[转]

    原文链接:原文 Bloom Filter是由Bloom在1970年提出的一种多哈希函数映射的快速查找算法.通常应用在一些需要快速判断某个元素是否属于集合,但是并不严格要求100%正确的场合. 一. 实 ...

  6. 利用JavaScript计算引擎进行字符串公式运算

    1.通过js计算引擎计算(java自带) 2.计算公式除了支持基本的方法之外还支持简单js脚本分支计算 3.通过设定map传入参数 4.默认返回最后一个计算结果,如果需返回特定值,将变量补写在公式最后 ...

  7. [LintCode]判断一个字符串是否包含另一个字符串的所有字符

    问题描述: 比较两个字符串A和B,确定A中是否包含B中所有的字符.字符串A和B中的字符都是 大写字母. 样例 给出 A = "ABCD" B = "ACD",返 ...

  8. 预留端口避免占用ip_local_reserved_ports

    问题描述:  业务遇到这个情况,在重启服务时,出现1986端口被占用而无法启动,非得等该端口释放后才启动成功. 问题分析: 1986端口被该服务器上的客户端随机选取源端口给占用掉了. 解决方案:  使 ...

  9. WPF教程二:布局之StackPanel面板

    应用程序界面设计中,合理的元素布局至关重要,它可以方便用户使用,并将信息清晰合理地展现给用户.WPF提供了一套功能强大的工具-面板(Panel),来控制用户界面的布局.你可以使用这些面板控件来排布元素 ...

  10. ★ java删除代码注释

    package com.witwicky.util; import java.io.BufferedReader; import java.io.BufferedWriter; import java ...