socket编程学习
socket: 也称作套接字,应用程序通常通过套接字向网络发出请求或者应答网络请求。
常用的套接字API函数:
1、socket():
函数原型为:int socket(int domain, int type, int protocol);
函数参数说明:
domain: 为创建的套接字指定协议集,例如:AF_INET(表示IPv4网络协议)、AF_INET6(表示IPv6)、AF_UNIX或者AF_LOCAL(表示本地套接字)。
type:SOCK_STREAM(可靠地面向流服务或流套接字)、SOCK_DGRAM(数据报文或者数据报文套接字)、SOCK_SEQPACKET(可靠的连续数据包服务)、SOCK_RAW(在网络层之上的原始协议)。
protocol:指定实际使用的传输协议。最常见的就是IPPROTO_TCP、IPPROTO_SCTP、IPPROTO_UDP、IPPROTO_DCCP。这些协议都在<netinet/in.h>中有详细说明。
如果该项为“0”的话,即根据选定的domain和type选择使用缺省协议。
返回值:如果发生错误,则返回-1,否则返回的是一个代表新分配的描述符的整数。
2、bind():
函数原型:bind()为一个套接字分配地址,当使用socket()创建套接字后,只赋予其所使用的协议,并未分配地址。在接受其它主机的连接前,必须先调用bind()为套接字分配一个地址。
函数原型为:int bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen);
函数参数说明:
sockfd:表示使用bind函数的套接字描述符。
my_addr:指向sockaddr结构(用于表示所分配地址)的指针。
addrlen:用socklen_t字段指定了sockaddr结构的长度。
返回值:如果发生错误,则返回-1,否则返回0。
3、listen():
当socket和一个地址绑定之后,listen()函数会开始监听可能的连接请求,但这是只能在有可靠数据流保证的时候使用,例如数据类型(SOCK_STREAM,SOCK_SEQPACKET)。
函数原型:int listen(int sockfd, int backlog);
函数参数说明:
sockfd:一个socket的描述符。
backlog:一个决定监听队列大小的整数,当有一个请求来到时,就会进入此监听队列,当队列满后,新的连接请求就会返回错误。
返回值:0表示成功,-1表示错误。
4、accept():
当应用程序监听来自其他主机的面对数据流的连接时,通过事件(比如Unix select()系统调用)通知它。必须用 accept()函数初始化连接。 Accept() 为每个连接创立新的套接字并从监听队列中移除这个连接。
函数原型:int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen)。
函数参数说明:
sockfd:监听的套接字描述符。
cliaddr:指向sockaddr结构体的指针,客户机地址信息。
addrlen:指向socklen_t的指针,确定客户机地址结构体的大小。
返回值:返回新的套接字描述符,如果出错就返回-1。进一步的通信必须通过这个套接字。
5、connect():
connect()系统调用为一个套接字设置参数连接,参数有文件描述符和主机地址。
有些类型的套接字是无连接的,大多数是使用UDP协议。对于这些套接字,连接时这样的:默认发送和接收数据的主机由给定的地址确定,可以使用 send()和 recv()。
返回值: 返回-1表示出错,0表示成功。
6、select():用于修整有如下情况的套接字列表:准备读,准备写或者是用错误。
7、poll():用于检查套接字的状态。套接字可以被测试,看是否可以写入、读取或是用错误。
8、getsockopt():用于查询指定的套接字一个特定的套接字选项的当前值。
9、setsockopt():用于为指定的套接字设定一个特定的套接字选项。
使用TCP的服务器:
设置一个简单的TCP服务器的步骤:
1、调用socket函数建立套接字。
2、调用bind函数把套接字绑定到一个监听端口上。注意bind函数需要接受一个sockaddr_in结构体作为参数,因此在调用bind函数之前, 程序要先声明一个 sockaddr_in结构体,用memset函数将其清零,然后将其中的sin_family设置为AF_INET,接下来,程序需要设置其sin_port成员变量,即监听端口。需要说明的是,sin_port中的端口号需要以网络字节序存储,因此需要调用htons函数对端口号进行转换(函数名是"host
to network short"的缩写)。
3、调用listen函数,使该套接字成为一个处在监听状态的套接字。
4、服务器可以通过accept函数接受客户端的连接请求。若没有收到连接请求,accept函数将不会返回并阻塞程序的执行。接收到连接请求后,accept函数会为该连接返回一个套接字描述符。accept函数可以被多次调用来接受不同客户端的连接请求,而且之前的连接仍处于监听状态——直到其被关闭为止。
5、服务器可以通过对send,recv或者对write,read等函数的调用来同客户端进行通信。
6、对于一个不再需要的套接字,可以使用close函数关闭它。
代码如下:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> int main()
{
struct sockaddr_in stSockAddr; //服务器网络地址结构体
//创建服务器端套接字--IPv4协议,面向可靠的字节流服务,TCP协议
int SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (SocketFD == -1) {
perror("can not create socket");
exit(EXIT_FAILURE);
} memset(&stSockAddr, 0, sizeof(struct sockaddr)); stSockAddr.sin_family = AF_INET; //设置为IP通信
stSockAddr.sin_port = htons(1200);//服务器的端口号
stSockAddr.sin_addr.s_addr = INADDR_ANY;//服务器IP地址--允许连接到所有本地地址上
//将套接字绑定到服务器的网络地址上
if (bind(SocketFD, (const struct sockaddr *)&stSockAddr, sizeof(struct sockaddr_in)) == -1) {
perror("error bind failed");
close(SocketFD);
exit(EXIT_FAILURE);
} //监听可能的连接请求,监听队列长度为10
if (listen(SocketFD, 10) == -1) {
perror("error listen failed");
close(SocketFD);
exit(EXIT_FAILURE);
} while (true) {
//accept()为每个连接创立新的套接字并从监听队列中移除这个连接,其返回值为新的套接字描述符
int ConnectFD = accept(SocketFD, NULL, NULL);
if (ConnectFD < 0) {
perror("error accept failed");
close(SocketFD);
exit(EXIT_FAILURE);
}
//调用shutdown只是进行了TCP断开,并没有释放文件描述符
shutdown(ConnectFD, SHUT_RDWR);
close(ConnectFD);
} close(SocketFD);
return 0;
}
使用TCP的客户端:
建立一个客户机的步骤如下:
1、调用socket()建立套接字。
2、用connect()连接到服务器,类似服务器端的操作,将sin_family设为AF_INET,sin_port设为服务器的监听端口(依然要以网络字节序),sin_addr设为服务器IP地址的(还是要用网络字节序)的sockaddr_in作为参数传入。
3、用send() 和 recv() 或者 write() 和 read()进行通信。
4、用close()终止连接。如果调用fork(), 每个进程都要用close()。
代码如下:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> int main()
{
struct sockaddr_in stSockAddr;
int Res; int SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (SocketFD == -1) {
perror("can not create socket");
exit(EXIT_FAILURE);
} memset(&stSockAddr, 0, sizeof(struct sockaddr_in)); stSockAddr.sin_family = AF_INET;
stSockAddr.sin_port = (1200);
Res = inet_pton(AF_INET, "192.168.1.4", &stSockAddr.sin_addr);
if (Res < 0) {
perror("error: first parameter is not a valid address family");
close(SocketFD);
exit(EXIT_FAILURE);
} else if (Res == 0) {
perror("second parameter does not contain valid ipaddress");
close(SocketFD);
exit(EXIT_FAILURE);
} if (connect(SocketFD, (const struct sockaddr *)&stSockAddr, sizeof(struct sockaddr_in)) == -1) {
perror("connect failed");
close(SocketFD);
exit(EXIT_FAILURE);
} shutdown(SocketFD, SHUT_RDWR);
close(SocketFD);
return 0;
}
使用UDP的服务器:
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h> int main()
{
int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
struct sockaddr_in sa;
char buffer[1024];
ssize_t recsize;
socklen_t fromlen; memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = INADDR_ANY;
sa.sin_port = htons(7654); if (bind(sock, (struct sockaddr *)&sa, sizeof(struct sockaddr))) {
perror("error bind failed");
close(sock);
exit(EXIT_FAILURE);
} while (true) {
puts("recv test...");
//用recvfrom接收给UDP端口7654的数据包
recsize = recvfrom(sock, (void *)buffer, 1024, 0, (struct sockaddr *)&sa, &fromlen);
if (recsize < 0) {
puts("....");
} printf("recsize : %d\n", recsize);
sleep(1);
printf("datagram : %s\n", buffer);
}
return 0;
}
使用UDP的客户端:
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h> int main()
{
int sock;
struct sockaddr_in sa;
int bytes_sent, buffer_length;
char buffer[100]; buffer_length = snprintf(buffer, sizeof(buffer), "Hello World\r\n"); sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (sock == -1) {
puts("can not create socket");
exit(EXIT_FAILURE);
} memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
//回环地址127.0.0.1
sa.sin_addr.s_addr = htonl(0x7f000001);
sa.sin_port = htons(7654); bytes_sent = sendto(sock, buffer, buffer_length, 0, (struct sockaddr *)&sa, sizeof(struct sockaddr_in));
if (bytes_sent < 0) {
puts("Error sending packet");
}
close(sock);
return 0;
}
socket编程学习的更多相关文章
- socket编程学习step1
socket学习参考链接,赞一个:http://blog.csdn.net/hguisu/article/details/7445768 sockets(套接字)编程有三种,流式套接字(SOCK_ST ...
- JAVA Socket 编程学习笔记(二)
在上一篇中,使用了 java Socket+Tcp/IP 协议来实现应用程序或客户端--服务器间的实时双向通信,本篇中,将使用 UDP 协议来实现 Socket 的通信. 1. 关于UDP UDP协 ...
- JAVA Socket 编程学习笔记(一)
1. Socket 通信简介及模型 Java Socket 可实现客户端--服务器间的双向实时通信.java.net包中定义的两个类socket和ServerSocket,分别用来实现双向连接的cli ...
- Socket编程学习之道:揭开Socket编程的面纱
对TCP/IP.UDP.Socket编程这些词你不会非常陌生吧?随着网络技术的发展.这些词充斥着我们的耳朵. 那么我想问: 1. 什么是TCP/IP.UDP? 2. S ...
- LInux下socket编程学习笔记
1.socket套接字: socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模 ...
- 记一次:Windows的Socket编程学习和分析过程
Socket编程依赖于:WS2_32.dll --- 服务端 --- .导入我们需要的函数 #incldue <windows.h> //#include<WinSock2.h> ...
- Android Socket编程学习笔记
http://blog.csdn.net/eyu8874521/article/details/8847173 度娘给出的描述:通常也称作"套接字",用于描述IP地址和端口,是一个 ...
- C++的socket编程学习
前言 不得不承认作为一个前端开发,仍有一个后台开发的梦.从socket通信开始学习,在工作之余补充学习点相关知识,记录下学习的过程. 服务端 服务器代码如下,在设置listen之后,通过accept获 ...
- BSD socket编程学习
1.socket简介 BSD是实现TCP/IP协议通信的软件系统,socket是应用编程接口,为app提供使用TCP/IP协议通信的接口. 网络层IP提供点到点服务(IP地址标识),传输层TCP和UD ...
随机推荐
- 错误描述:请求“System.Data.SqlClient.SqlClientPermission, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089”类型的权限已失败
错误描述:请求“System.Data.SqlClient.SqlClientPermission, System.Data, Version=2.0.0.0, Culture=neutral, Pu ...
- mongoengine
http://docs.mongodb.org/ecosystem/drivers/python/ http://www.cnblogs.com/holbrook/archive/2012/03/11 ...
- volley post非json格式数据并获取json数据
在使用JsonObjectRequest时无法post非json格式的数据,因而采用StringRequest获取到相应的数据后再转为json格式的数据. //这里的上下文需要讨论 private s ...
- MFC 对话框添加菜单
1.在Resource View 里右击菜单里选择Add Resource,选择menu,添加一个IDR_MENU1的菜单.在编辑器编辑菜单,添加菜单项,命名各个菜单项的ID. 2.在所要添加菜单的对 ...
- python pexpect 学习与探索
pexpect是python交互模块,有两种使用方法,一种是函数:run另外一种是spawn类 1.pexpect module 安装 pexpect属于第三方的,所以需要安装, 目前的版本是 3. ...
- 22. javacript高级程序设计-高级技巧
1. 高级技巧 1.1 函数 l 可以使用惰性载入函数,将任何分支推迟到第一个调用函数的时候 l 函数绑定可以让你创建始终在指定环境中运行的函数,同时函数柯里化可以让你创建已经填写了某些参数的函数 l ...
- ffmpeg-20160726-bin.7z
ESC 退出 0 进度条开关 1 屏幕原始大小 2 屏幕1/2大小 3 屏幕1/3大小 4 屏幕1/4大小 S 下一帧 [ -2秒 ] +2秒 ; -1秒 ' +1秒 下一个帧 -> -5秒 f ...
- Java for LeetCode 226 Invert Binary Tree
Invert a binary tree. 4 / \ 2 7 / \ / \ 1 3 6 9 to 4 / \ 7 2 / \ / \ 9 6 3 1 Trivia: This problem wa ...
- win7,ubuntu双系统——重装win7后如何恢复ubuntu引导
磁盘分区——windows 7自带分区工具实现 磁盘分区——PQ硬盘分区魔术师 win7,ubuntu双系统的安装——正式安装 win7,ubuntu双系统的安装——卸载ubuntu 讲述了我的 w ...
- mybatis 获取自增ID
在Mybatis Mapper文件中添加属性“useGeneratedKeys”和“keyProperty”,其中keyProperty是Java对象的属性名,而不是表格的字段名. <inser ...