基础知识部分:http://www.cnblogs.com/Jimmy1988/p/7839940.html

1. 基本流程

Process Client Server Comment
socket() 创建socket文件描述符 同← 通信双方都需建立
socket文件描述符是应用层通信接口
bind() 可选
一般不绑定,由内核自动分配
必选
IP地址不能为公网地址
远程:一般设置为"0.0.0.0"或 INADDR_ANY
局域网:可设置为内网地址
详细可见:
https://www.cnblogs.com/ok-lanyan/articles/2634242.html
Listen() 可选,一般不监听 必选
使socket处于监听网络状态
阻塞等待
connect() 向服务端发起链接请求 包含目标主机的IP和Port
accept() 服务端接受链接请求
接受链接后,使用一个新的socket描述符,
使服务端可接受多个链接
可以提取客户端的IP和Port
Send/Recv() 进行数据包的发送和接受 同← socket同样可以认为是文件,
可以直接read/write()
close() 关闭socket链接 同← 可以分开关闭读/写操作

2. API

1). Socket()

#include <sys/socket.h>

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

/* Return Value:
* If successed: A file descriptor for new socket
* else : -1
*/

①. domain:

用于选择本次通信的协议簇(地址簇);

其详细定义见 /usr/include/bits/socket.h, 常用的宏如下:

Name Purpose Man page
AF_UNIX,
AF_LOCAL
Local communication unix(7)
AF_INET IPv4 Internet protocols ip(7)
AF_INET6 IPv6 Internet protocols ipv6(7)
AF_IPX IPX - Novell protocols
AF_NETLINK Kernel user interface device netlink(7)

②. type

协议类型

详细信息见/usr/include/bits/socket_types.h,常用的如下:

Type Purpose
SOCK_STREAM Provides sequenced, reliable, two-way, connection-based byte streams.
An out-of-band data transmission mechanism may be supported.
SOCK_DGRAM Supports datagrams (connectionless,
unreliable messages of a fixed maximum length).

③. protocol

一般由系统自动选择,通常设置为0

2). bind()

当使用socket()创建一个socket后,存在着一个name space,但是没有内存地址与其关联;

本函数的目的就是为了分配内存地址给socket

#include <sys/socket.h>

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)

/* Return Value:
* If successsed: 0
* else: -1
*/

①. socktfd

socket()函数返回的socket文件描述符

②. addr

分配给socket的地址空间首地址;

根据协议的不同,结构体定义不同,可以使用man 7 ip/ipv6/etc..查看;

一般的定义形式如下:

/* Structure describing a generic socket address.  */
struct sockaddr
{
__SOCKADDR_COMMON (sa_); /* Common data: address family and length. */
char sa_data[14]; /* Address data. */
}; /*IF flags = AF_INET, 即IPv4*/
struct sockaddr_in {
sa_family_t sin_family; /* address family: AF_INET */
in_port_t sin_port; /* port in network byte order */
struct in_addr sin_addr; /* internet address */
}; /* Internet address. */
struct in_addr {
uint32_t s_addr; /* address in network byte order */
};

③. addrlen

地址长度,一般使用sizeof(xx)

3). Listen()

#include <sys/socket.h>

int listen(int sockfd, int backlog)

/*
* backlog: 请求排队的最大长度
*/ /* Return Value
* If successed: 0
* else: -1
*/

4). connect()

#include <sys/socket.h>

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

/* Return Value
* If successed: 0
* else: -1
*/

5). accept()

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

/* Return Value
* If successed: 有效的接收到的socket描述符
* else: -1
*/

6). read/write()

读写时,可以把socket看成普通文件,因此读写的方式与普通文件相同:

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);

7). send/recv()

针对面向连接的socket的读写操作

#include <sys/socket.h>

ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t recv(int sockfd, void *buf, size_t len, int flags); /* Arguments:
* 1. buf: 数据存放位置
* 2. len: 数据发送/接收大小
* 3. flags: 见下面
*/ /* Return Value
* If successed: 发送/接收的数据量
* else: -1
*/

**flags: **

enum
{
MSG_OOB = 0x01, /* Process out-of-band data. */
#define MSG_OOB MSG_OOB
MSG_PEEK = 0x02, /* Peek at incoming messages. */
#define MSG_PEEK MSG_PEEK
MSG_DONTROUTE = 0x04, /* Don't use local routing. */
#define MSG_DONTROUTE MSG_DONTROUTE
#ifdef __USE_GNU
/* DECnet uses a different name. */
MSG_TRYHARD = MSG_DONTROUTE,
# define MSG_TRYHARD MSG_DONTROUTE
#endif
MSG_CTRUNC = 0x08, /* Control data lost before delivery. */
#define MSG_CTRUNC MSG_CTRUNC
MSG_PROXY = 0x10, /* Supply or ask second address. */
#define MSG_PROXY MSG_PROXY
MSG_TRUNC = 0x20,
#define MSG_TRUNC MSG_TRUNC
MSG_DONTWAIT = 0x40, /* Nonblocking IO. */
#define MSG_DONTWAIT MSG_DONTWAIT
MSG_EOR = 0x80, /* End of record. */
#define MSG_EOR MSG_EOR
MSG_WAITALL = 0x100, /* Wait for a full request. */
#define MSG_WAITALL MSG_WAITALL
MSG_FIN = 0x200,
#define MSG_FIN MSG_FIN
MSG_SYN = 0x400,
#define MSG_SYN MSG_SYN
MSG_CONFIRM = 0x800, /* Confirm path validity. */
#define MSG_CONFIRM MSG_CONFIRM
MSG_RST = 0x1000,
#define MSG_RST MSG_RST
MSG_ERRQUEUE = 0x2000, /* Fetch message from error queue. */
#define MSG_ERRQUEUE MSG_ERRQUEUE
MSG_NOSIGNAL = 0x4000, /* Do not generate SIGPIPE. */
#define MSG_NOSIGNAL MSG_NOSIGNAL
MSG_MORE = 0x8000, /* Sender will send more. */
#define MSG_MORE MSG_MORE
MSG_WAITFORONE = 0x10000, /* Wait for at least one packet to return.*/
#define MSG_WAITFORONE MSG_WAITFORONE MSG_CMSG_CLOEXEC = 0x40000000 /* Set close_on_exit for file
descriptor received through
SCM_RIGHTS. */
#define MSG_CMSG_CLOEXEC MSG_CMSG_CLOEXEC
};

8). close/shutdown()

两种方式关闭socket

I. close()

完全关闭socket通道,包括读和写

#include <unistd.h>

int close(int fd);

II. shutdown()

具备更强的灵活性,可选择性关闭读或写

 #include <sys/socket.h>

int shutdown(int sockfd, int how);

how:

  • how=0: 只关闭读通道;
  • how=1: 只关闭写通道
  • how=2: 关闭读写通道

9). getsockname/getpeername()

I. 获取socket的本地地址

要求:已完成绑定本地IP

#include <sys/socket.h>

int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

/* Return Value
* If successed: 0
* else: -1
*/

II. 获取socket远程信息

要求:该socket已经完成远程连接

#include <sys/socket.h>

int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

/* Return Value
* If successed: 0
* else: -1
*/

10). 获取本机IP地址等信息

#include <ifaddrs.h>

int getifaddrs(struct ifaddrs **ifap);
void freeifaddrs(struct ifaddrs *ifa) /*Return value:
* If successed:0
* else: -1
*/ struct ifaddrs {
struct ifaddrs *ifa_next; /* Next item in list */
char *ifa_name; /* Name of interface */
unsigned int ifa_flags; /* Flags from SIOCGIFFLAGS */
struct sockaddr *ifa_addr; /* Address of interface */
struct sockaddr *ifa_netmask; /* Netmask of interface */
union {
struct sockaddr *ifu_broadaddr; /* Broadcast address of interface */
struct sockaddr *ifu_dstaddr;
/* Point-to-point destination address */
} ifa_ifu;
#define ifa_broadaddr ifa_ifu.ifu_broadaddr
#define ifa_dstaddr ifa_ifu.ifu_dstaddr
void *ifa_data; /* Address-specific data */
};

3. 示例代码

本次实现client/server两端的实时聊天功能,彼此不影响,可随时发送/接收对方数据;

当输入"quit”后,结束本次链接。

1. Client.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <errno.h> #define SIZE 1024
#define PORT 12345
//#define IP_ADDR "192.168.139.129" #define IP_ADDR "139.196.121.132"
//#define IP_ADDR "47.89.246.154" int sockfd; void *snd(void)
{
int len = 0;
char buf[SIZE];
while(1)
{
memset(buf,'\0', sizeof(buf));
printf("\nInput msg send to server: ");
fgets(buf, SIZE, stdin);
if(buf[0] != '\0')
{
len = send(sockfd, buf, sizeof(buf), 0);
if(len < 0)
{
printf("SND: Some Error occured or disconnection!\n");
break;
} if(!strncasecmp(buf, "quit",4))
{
printf("SND: sub thread has quit!\n");
break;
}
printf("\nSend msg: %s \n", buf);
}
} pthread_exit(NULL);
} void *rcv(void)
{
int len=0;
char buf[SIZE]; while(1)
{
memset(buf,'\0', sizeof(buf)); len = recv(sockfd, buf, SIZE, 0); if(len < 0)
{
printf("RCV: Some error occured!\n");
break;
} if(!strncasecmp(buf, "quit",4))
{
printf("RCV: sub thread has quit!\n");
break;
} printf("\nThe received msg:%s\n", buf);
} pthread_exit(NULL);
} int main(int argc, char *argv[])
{
int ret; //1. create socket
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(-1 == sockfd)
{
perror("socket");
exit(EXIT_FAILURE);
} //2. bind the ip addr
struct sockaddr_in dest_addr;
memset(&dest_addr, 0, sizeof(struct sockaddr_in)); dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(PORT);
dest_addr.sin_addr.s_addr = inet_addr(IP_ADDR); /*
ret = bind(sockfd, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_in));
if(-1 == ret)
{
perror("bind");
exit(EXIT_FAILURE);
}
*/ //3. request the connection
ret = connect(sockfd, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
if(-1 == ret)
{
perror("connect");
exit(EXIT_FAILURE);
}
printf("Connect the server(IP:%s) successed!\n", IP_ADDR); //5. send/receive the message
pthread_t tid1, tid2; if( 0 != pthread_create(&tid1, NULL, (void *)*snd, NULL))
{
perror("pthread_create");
exit(errno);
} if( 0 != pthread_create(&tid2, NULL, (void *)*rcv, NULL))
{
perror("pthread_create");
exit(errno);
} pthread_join(tid1, NULL);
pthread_join(tid2, NULL); return 0;
}

2. Server.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/ip.h> #define SIZE 1024
#define PORT 12345
//#define IP_ADDR "192.168.139.129"
#define IP_ADDR "139.196.121.132" int main(int argc, char *argv[])
{
int ret;
pthread_t tid;
int sockfd; //1. create socket
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(-1 == sockfd)
{
perror("socket");
exit(EXIT_FAILURE);
} //2. bind the ip addr
struct sockaddr_in local_addr;
memset(&local_addr, 0, sizeof(struct sockaddr_in)); local_addr.sin_family = AF_INET;
local_addr.sin_port = htons(PORT);
local_addr.sin_addr.s_addr = inet_addr(IP_ADDR); ret = bind(sockfd, (struct sockaddr *)&local_addr, sizeof(struct sockaddr_in));
if(-1 == ret)
{
perror("bind");
exit(EXIT_FAILURE);
} //3. listen the connection
unsigned int lisnum = 5;
ret = listen(sockfd, lisnum);
if(-1 == ret)
{
perror("listen");
exit(EXIT_FAILURE);
}
printf("Wait for client connection!\n"); //4. accept the connection
int new_fd;
socklen_t len;
struct sockaddr_in client_addr; new_fd = accept(sockfd, (struct sockaddr *)&client_addr, &len);
if(-1 == new_fd)
{
perror("accept");
exit(EXIT_FAILURE);
} else
{
// printf("Server got connection: \n\tAddress:%s\tPort:%d\tSocket=%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), new_fd);
} //5. send/receive the message
char buf[SIZE];
ssize_t length;
pid_t pid;
pid = fork();
if(pid == -1)
{
perror("fork");
exit(EXIT_FAILURE);
} if(pid == 0)
{
while(1)
{
memset(buf, '\0', SIZE);
printf("Pls input the msg to send: ");
fgets(buf, SIZE, stdin); if((length=strlen(buf)) < 0)
{
printf("send error, the length=%d\n", length);
break;
} length = send(new_fd, buf, sizeof(buf), 0); if(!strncasecmp(buf, "quit", 4))
{
printf("Snd: close the connection!\n");
break;
}
}
} else
{
while(1)
{
memset(buf, '\0', SIZE);
length = recv(new_fd, buf, SIZE, 0); if(length >= 0)
{
printf("\nReceive msg: %s\n", buf);
} else
{
printf("Error occured\n");
break;
} if(!strncasecmp(buf, "quit", 4))
{
printf("Recv: close the connection!\n");
break;
}
} } //Close the socket
close(sockfd);
close(new_fd); return 0;
}

Socket编程 - API的更多相关文章

  1. 【TCP/IP】之Java socket编程API基础

    Socket是Java网络编程的基础,深入学习socket对于了解tcp/ip网络通信协议很有帮助, 此文讲解Socket的基础编程.Socket用法:①.主要用在进程间,网络间通信. 文章目录如下: ...

  2. 转 网络编程学习笔记一:Socket编程

    题外话 前几天和朋友聊天,朋友问我怎么最近不写博客了,一个是因为最近在忙着公司使用的一些控件的开发,浏览器兼容性搞死人:但主要是因为这段时间一直在看html5的东西,看到web socket时觉得很有 ...

  3. Socket编程实践(2) Socket API 与 简单例程

    在本篇文章中,先介绍一下Socket编程的一些API,然后利用这些API实现一个客户端-服务器模型的一个简单通信例程.该例子中,服务器接收到客户端的信息后,将信息重新发送给客户端. socket()函 ...

  4. 网络编程socket基本API详解(转)

    网络编程socket基本API详解   socket socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用已实现进程在网络中通信. socket ...

  5. socket编程 ------ BSD socket API

    伯克利套接字(Berkeley sockets),也称为BSD Socket.伯克利套接字的应用编程接口(API)是采用C语言的进程间通信的库,经常用在计算机网络间的通信. BSD Socket的应用 ...

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

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

  7. socket编程学习step1

    socket学习参考链接,赞一个:http://blog.csdn.net/hguisu/article/details/7445768 sockets(套接字)编程有三种,流式套接字(SOCK_ST ...

  8. socket编程基础

    socket编程 什么是socket 定义 socket通常也称作套接字,用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过套接字向网络发出请求或者应答网络请求. socket起源于Unix ...

  9. Java Socket编程

    Java最初是作为网络编程语言出现的,其对网络提供了高度的支持,使得客户端和服务器的沟通变成了现实,而在网络编程中,使用最多的就是Socket.像大家熟悉的QQ.MSN都使用了Socket相关的技术. ...

随机推荐

  1. ReactJS 官网案例分析

    案例一.聊天室案例 /** * This file provided by Facebook is for non-commercial testing and evaluation * purpos ...

  2. 蚂蚁男孩.队列组件(Framework.Mayiboy.Queue)

    它能做什么 主要是用来方便使用队列而诞生,该组件封装了Queue和Redis中的队列,能够通过简单配置就可以高效快速使用起来. 使用说明 一.    下载源码,自己手动编译,手动引用必要的程序集.(需 ...

  3. Python: pyinstaller打包exe(含file version信息)

    最近项目上一直都是用Spyder直接运行.py文件的方式来执行每日的自动化程序,每天都要手动去点击Run来执行一次,所以考虑把.py文件直接打包成exe,然后用windows的task schedul ...

  4. devexpress 严重性 代码 说明 项目 文件 行 禁止显示状态 错误 “lc.exe”已退出,代码为 -1。

    将licensens.licx删除,就能正常运行

  5. 工信部公示网络安全示范项目 网易云易盾“自适应DDoS攻击深度检测和防御系统”入选

    本文由  网易云发布. 工信部官网 2017年年底,经专家评审和遴选,中华人民共和国工业和信息化部(以下简称“工信部”)公示了2017年电信和互联网行业网络安全试点示范项目,网易云易盾的“自适应DDo ...

  6. JQuery Mobile - 解决动态更新页面内容,CSS失效问题!

    今天编写JQuery Mobile程序,需要对数组数据动态创建,并且每条数据对应一个复选框,于是我很顺利写了一个Demo,当我运行时候发现,和我期望的不一样!复选框确实创建出来了,但是却没有CSS效果 ...

  7. Comparable接口——容器中自定义类排序

    1.容器TreeMap,默认根据Key对象中某个属性的从小到大排列元素. (1)如下代码示例,Key是整型数字,所以按照其从小到大的顺序排列 public class TestTreeMap { pu ...

  8. jzoj5945

    這題是均分紙牌求方案數 我們可以分2種情況討論: 1.當前面部分的平均值>=現在我們要的值 那麼我們可以把所有牌都放到第i個點,現在若有k張牌,則要把k−i∗avek-i*avek−i∗ave張 ...

  9. Django(出版社功能)

    day62 day62 2018-05-02  1. 内容回顾     Django         1. 安装             1. Django版本 1.11.xx            ...

  10. Java程序员的日常—— Spring Boot单元测试

    关于Spring boot 之前没有用Spring的时候是用的MockMvc,做接口层的测试,原理上就是加载applicationContext.xml文件,然后模拟启动各种mybatis\连接池等等 ...