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;
}

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

  1. ZT Linux系统环境下的Socket编程详细解析

    Linux系统环境下的Socket编程详细解析 来自: http://blog.163.com/jiangh_1982/blog/static/121950520082881457775/ 什么是So ...

  2. Linux下的C Socket编程 -- server端的继续研究

    Linux下的C Socket编程(四) 延长server的生命周期 在前面的一个个例子中,server在处理完一个连接后便会立即结束掉自己,然而这种server并不科学啊,server应该是能够一直 ...

  3. Linux下的C Socket编程 -- server端的简单示例

    Linux下的C Socket编程(三) server端的简单示例 经过前面的client端的学习,我们已经知道了如何创建socket,所以接下来就是去绑定他到具体的一个端口上面去. 绑定socket ...

  4. Linux下的C Socket编程 -- 获取对方IP地址

    Linux下的C Socket编程(二) 获取域名对应的IP地址 经过上面的讨论,如果我们想要连接到远程的服务器,我们需要知道对方的IP地址,系统函数gethostbyname便能够实现这个目的.它能 ...

  5. Linux下的C Socket编程 -- 简介与client端的处理

    Linux下的C Socket编程(一) 介绍 Socket是进程间通信的方式之一,是进程间的通信.这里说的进程并不一定是在同一台机器上也有可能是通过网络连接的不同机器上.只要他们之间建立起了sock ...

  6. 第九章:Python高级编程-Python socket编程

    第九章:Python高级编程-Python socket编程 Python3高级核心技术97讲 笔记 9.1 弄懂HTTP.Socket.TCP这几个概念 Socket为我们封装好了协议 9.2 cl ...

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

    看了Linux程序设计4中文版,学习了多线程编程和socket编程.本文的程序参考自Linux程序设计4的第15章. 设计了一个客户端程序,一个服务端程序.使用TCP协议进行数据传输. 客户端进程创建 ...

  8. 【Linux编程】socket编程

    套接字是通信端点的抽象.文件描写叙述符用open函数创建,而套接字描写叙述符用socket函数创建.socket函数原型例如以下: int socket(int domain, int type, i ...

  9. 学习笔记(10) : Socket 编程典型代码积累

    网络编程实现的机制:   服务器端: 申请一个socket 绑定到一个IP地址和端口上 开启侦听,等待接受连接   客户端: 申请一个socket 连接服务器(指明IP.端口)   服务器端: 接收到 ...

随机推荐

  1. CentOS 6.5 无网环境安装R及Rstudio的方法的方法

    在生产环节,一般是不联网的,下面介绍在无望环境如何安装R及R-studio 1.  安装CentOS for R语言的基础环境 1.1 libpng,X11,libjpeg等支持 yum -y ins ...

  2. Javascript中DOM技术的的简单学习

    第十四课DOM技术概述1:DOM概述 文档对象模型DOM(Document Object Model)定义访问和处理HTML文档的标准方法.DOM 将HTML文档呈现为带有元素.属性和文本的树结构(节 ...

  3. jmap命令(Java Memory Map)(转)

    JDK内置工具使用 一.javah命令(C Header and Stub File Generator) 二.jps命令(Java Virtual Machine Process Status To ...

  4. Android中使用自定义View实现下载进度的显示

    一般有下载功能的应用都会有这样一个场景,需要一个图标来标识不同的状态.之前在公司的项目中写过一个,今天抽空来整理一下. 一般下载都会有这么几种状态:未开始.等待.正在下载.下载结束,当然有时候会有下载 ...

  5. Tomcat远程调试

    1.如果tomcat在Windows下 打开%CATALINE_HOME%/bin下的文件catalina.bat,加入下面这行: set CATALINA_OPTS=-server -Xdebug ...

  6. 3D碰撞检测

    为了确保任何区域的空间不被多于1个物体占用,我们需要基于物体间的空间信息来做碰撞检测. 碰撞检测中重要的事情是有大量的测试,因此需要理由GPU资源. 例如:如果我们有n个物体,一个物体将会碰撞n-1个 ...

  7. SQLServer公历转农历函数(1900年-2049年)

    ALTER   FUNCTION   [dbo].[f_SysGetLunar](      @solarDay   DATETIME)            RETURNS   varchar(20 ...

  8. ubuntu下安装Node.js(源码安装)

    最近使用hexo的过程中出现了问题,中间载nodejs安装的时候也耽误了些许时间,所以在此记录一下安装的过程. 环境:ubuntu14.0.4LTS,安装nodejs版本node-v0.10.36.t ...

  9. 九宫格抽奖HTML+JS版

    <html> <head> <meta http-equiv="Content-Type" content="text/html; char ...

  10. 用issnode+IIS来托管NodeJs Server

    用issnode+IIS来托管NodeJs Server之一:安装篇 用issnode+IIS来托管NodeJs Server之二:移植 用issnode+IIS来托管NodeJs Server之三: ...