一、Socket通信:
1. 含义:
Socket 是在应用层和传输层之间的一个抽象层,它把 TCP/IP 层复杂的操作抽象为几个简单的接口,供应用层调用实现进程在网络中的通信。
2. 通信流程:
3. Socket通信部分接口说明:1. socket()
功 能:创建套接字
原 型:int socket(int domain, int type, int protocol);
参 数:
domain:协议族,通常为AF_INET,表示TCP/IP协议
type:socket类型,如:SOCK_STREAM(指TCP)和SOCK_DGRAM(指UDP)等等
protocol:套接口所用的协议,一般为0
返回值:
成功:socket文件描述符
失败:-1,并设置errno
2. bind()
功 能:将套接字和指定的端口相连
原 型:int bind(int sock_fd, struct sockaddr_in *my_addr, int addrlen);
参 数:
sock_fd:socket文件描述符
my_addr:设置服务器信息的sockaddr_in结构体指针
addrlen:sockaddr_in结构体的长度
返回值:
成功:0
失败:-1,并设置errno
说 明:
struct sockaddr_in{
short int sin_family;//网络通信网络层协议 AF_INET
unsigned short int sin_port;//端口
struct in_addr sin_addr;//IP地址
unsigned char sin_zero[8];//让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节
};
3. connect()
功 能:连接服务器请求(客户端使用)
原 型:int connect(int sock_fd, struct sockaddr *serv_addr,int addrlen);
参 数:
sock_fd:socket文件描述符
serv_addr:包含远端主机IP地址和端口号的指针
addrlen:sockaddr_in结构体的长度
返回值:
成功:0
失败:-1,并设置errno
4. listen()
功 能:创建一个套接口并监听申请的连接
原 型:int listen(int sock_fd, int backlog);
参 数:
sock_fd:socket文件描述符
backlog:请求队列中允许的最大请求数
返回值:
成功:0
失败:-1,并设置errno
5. accecpt()
功 能:接受客户端的服务请求
原 型:int accept(int sock_fd, struct sockadd_in* addr, int addrlen);
参 数:
sock_fd:被监听的socket文件描述符
addr:包含客户端IP地址和端口号的指针
addrlen:sockaddr_in结构体的长度
返回值:
成功:客户端套接字描述符
失败:-1,并设置errno
6. write()
功 能:写入数据到fd中
原 型:ssize_t write(int fd,const void *buf,size_t nbytes);
参 数:
fd:socket文件描述符
buf:字符串数据地址
nbytes:字符串数据大小
返回值:
实际写入的字节数,小于0为写入错误
6、read()
功 能:从fd中读取数据
原 型:ssize_t read(int fd,void *buf,size_t nbyte)
参 数:
fd:socket文件描述符
buf:字符串数据地址
nbyte:字符串数据大小
返回值:
>0: 实际读取的大小
=0:读到末尾了
<0:读取错误
8、close()
功 能:关闭套接字
原 型:int close(sock_fd);
参 数:
sock_fd:要关闭的socket文件描述符
返回值:
成功:0
失败:-1
二、线程部分接口说明:注意:Linux系统中使用线程库,编译时要加-lpthread,例如:gcc server.c -o server -lpthread
1. pthread_create()
功 能:创建线程
原 型:int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
参 数:
thread:线程的TID号,唯一的
attr:线程的属性
start_routine:任务函数指针,指向的函数类型 : void *func(void *)
arg:传递给任务函数使用的参数
返回值:
成功:0
失败:错误编号
2. pthread_exit()
功 能:终止调用它的线程并返回一个指向某个对象的指针(常与pthread_join()一起使用)
原 型:void pthread_exit(void *retval);
参 数:
retval:线程的退出状态值
返回值:
无
3. pthread_join()
功 能:以阻塞的方式等待指定的线程结束
原 型:int pthread_join(pthread_t thread, void **retval);
参 数:
thread:等待的线程的TID号
retval:用户定义的指针,用来存储被等待线程的返回值
返回值:
成功:0
失败:错误编号
4. pthread_cancel()
功 能:线程的取消
原 型:int pthread_cancel(pthread_t thread);
参 数:
thread:取消的线程的TID号
返回值:
成功:0
失败:错误编号
三、部分代码int main()
{
//1.创建网络的通信对象
socket_fd = socket(AF_INET,SOCK_STREAM,0);
if(socket_fd
{
perror("socket error!");
return -1;
}
//2.定义服务器注册的网络端口 和 网络 IP 结构体
struct sockaddr_in server_addr,client_addr;
int len = sizeof(client_addr);
server_addr.sin_family = AF_INET;//设置网络层协议
server_addr.sin_port = htons(6666);//设置端口号
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");//设置IP地址
//3.绑定服务器的IP地址
int ret = bind(socket_fd,(struct sockaddr *)&server_addr,sizeof(server_addr));
if(ret != 0)
{
perror("bind error!");
return -1;
}
//4.把服务器socket,设置为监听模式
ret = listen(socket_fd,5);
if(ret != 0)
{
perror("listen error!");
return -1;
}
printf("等待客户端的连接请求:\n");
//5.接收客户端的连接请求
client_fd = accept(socket_fd,(struct sockaddr *)&client_addr,&len);
if(client_fd
{
perror("socket error!");
return -1;
}
printf("ip:%s\n",inet_ntoa(client_addr.sin_addr));
printf("port:%d\n",ntohs(client_addr.sin_port));
//创建线程
pthread_t tid;
pthread_create(&tid,NULL,sock_read,NULL);
pthread_detach(tid); //设置为分离属性
//5.发送网络数据
char buf[1024] = {0};
while(1)
{
scanf("%s",buf);
write(client_fd,buf,strlen(buf));
}
close(socket_fd);
return 0;
}
运行命令:./server和./client
四、实现效果
五、总结
后续跟新以下Demo:
六、项目结构图