自己敲了几遍~~,对于我这个小白来说(= _ =),花了大功夫来理解(基本概念我看了老师给的PPT= _=)
我怕老师上课讲的时候我跟不上,所以就预习了一下+ _ +
主要的步骤:(服务器)
1. 创建一个socket,用函数socket()
2. 绑定IP地址、端口等信息到socket上,用函数bind()
3.设置允许的最大连接数,用函数listen()
4.接收客户端上来的连接,用函数accept()
5.收发数据,用函数send()和recv(),或者read()和write()
6.关闭网络连接
关于这些函数的功能和用法 可以看——>https://blog.csdn.net/letueodiandian/article/details/4450586
一开始没懂套接字,我看了这篇文章——>https://blog.csdn.net/u012291393/article/details/38871287?utm_source=blogxgwz2
还有一些我没见过的数据类型我也搜了一下——>https://blog.csdn.net/Qiana_/article/details/79552087
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <assert.h>
#define PORT 9999
void receiveData(int client_socket)
{
char buf[101];
while(1)
{
int ret = read(client_socket,buf,100);
if(ret == -1)
{
break;
}
if(ret == 0)
{
printf("客户端退出\n");
break;
}
buf[ret - 1] = '\0';
printf("从客户端读到的消息是:%s\n",buf);
}
}
void * sendData(void * v)
{
int client_socket = *(int *)v;
char buf[101];
while(1)
{
fgets(buf,100,stdin);
write(client_socket,buf,strlen(buf));
}
return NULL;
}
int main()
{
/*创建一个套接字
*socket函数原型:int socket(int family,int type,int protocol);
*int family:对于ipv4,地址族指定为AF_INET
*对于TCP协议:type参数指定为SOCK_STREAM,表示面向流的传输协议。如果是UDP协议,则type参数指定SOCK_DGRAM,表示面向数据报的传输协议
*protocol参数直接指定为0
*/
int listen_fd = socket(AF_INET,SOCK_STREAM,0);
if(listen_fd == -1)
{
perror("socket");
}
/*使用socket进行通信的时候,我们需要指定三个元素:通信域(地址族)、IP地址、端口号,这三个元素由SOCKADDR_IN结构体定义
*socketaddr_in的初始化
*首先将整个结构体清零
*设置地址类型为AF_INET,网络地址为INADDR_ANY
*因为服务器可能有多个网卡,每个网卡也可以绑定多个IP地址,这样可以设置在所有的IP地址上监听。
*端口号为SERV_PORT,定义为8000
*/
struct sockaddr_in addr;
memset(&addr,0,sizeof(addr));
addr.sin_family = AF_INET; //使用ipv4地址族
addr.sin_port = htons(PORT); //设置端口,要注意转换成网络字节序
addr.sin_addr.s_addr = htonl(INADDR_ANY); //设置监听的IP地址,INADDR_ANY表示可以监听本机任意IP地址
/*当调用socket()函数创建套接字后,该套接字并没有与本机的地址和端口等信息相连
*bind()函数就是件套接字与指定的端口相连
*函数原型:int bind(int sockfd,const sockaddr *my_addr,socklen_t addrlen);
*int sockfd:第一个参数指的是为调用socket函数后返回的文件包描述符
*my_addr:第二个参数为指向sockaddr_in结构体的指针(该结构体中保存端口和IP地址信息)
*addlen:第三个参数为sockaddr_in结构体的长度
*/
int ret = bind(listen_fd,(const struct sockaddr *)&addr,sizeof(addr));
if(ret == -1)
{
perror("bind");
}
/*服务器必须等待客户的连接请求,listen()函数用于实现该功能
*函数原型:int listen(int sockfd,int backlog);
*int sockfd:第一个参数为调用socket函数获得的套接字的文件描述符信息
*int backlog:第二个参数是连接请求后,在服务器接受该请求时的等待队列中的连接数
*/
ret = listen(listen_fd,5);
if(ret == -1)
{
perror("listen");
}
/*accept()函数用于接受客户机的连接请求
*accept函数将从连接请求队列中获得连接信息,创建新的套接字,新创建的套接字用于服务器与客户机的通信,而原来的套接字仍处于监听状态
*函数原型:int accpet(int sockfd,struct sockaddr *addr,socklen_t *addrlen)
*第一个参数为监听的套接字描述符
*第二个参数addr指向结构体的指针
*第三个参数adrlen为addr参数指向空间内存的长度
*/
struct sockaddr_in client_addr;
int addrlen;
int client_socket = accept(listen_fd,(struct sockaddr *)&client_addr,&addrlen);
if(client_socket == -1)
{
perror("accept");
}
//将一个十进制的网络字节序转换成点分十进制的IP的格式字符串
printf("连接的客户端IP地址:%s,端口:%d\n",inet_ntoa(client_addr.sin_addr),client_addr.sin_port);
//pthread_create()创建多线程
pthread_t thread; //pthread_t是一种数据类型,用于声明线程ID
ret = pthread_create(&thread,NULL,sendData,&client_socket);
assert(ret == 0);
receiveData(client_socket);
close(client_socket);
close(listen_fd);
return 0;
}
主要步骤:(客户端)
1.创建一个socket,用函数socket()
2.设置要连接的对方的IP地址和端口等属性
3.连接服务器,用函数connect()
4.收发数据,用函数send()和recv(),或者 read()和write()
5.关闭网络连接
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <assert.h>
#define PORT 9999
void * receiveData(void * v)
{
int con_fd = *(int *)v;
char buf[101];
while(1)
{
int ret = read(con_fd,buf,100);
buf[ret] = '\0';
printf("从服务器收到的消息:%s\n",buf);
}
return NULL;
}
void sendData(int con_fd)
{
char buf[101];
while(1)
{
fgets(buf,100,stdin);
write(con_fd,buf,strlen(buf));
}
}
int main(int argc,char *argv[])
{
if(argc != 3)
{
printf("Usage:%s IP port\n", argv[0]);
return -1;
}
int con_fd = socket(AF_INET,SOCK_STREAM,0);
if(con_fd == -1)
{
perror("socket");
}
struct sockaddr_in addr;
int port = atoi(argv[2]);
memset(&addr,0,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
int ret = connect(con_fd,(const struct sockaddr *)&addr,(socklen_t)sizeof(addr));
if(ret == -1)
{
perror("connect");
return -1;
}
printf("连接到服务器......\n");
pthread_t thread;
ret = pthread_create(&thread,NULL,receiveData,&con_fd);
assert(ret == 0);
sendData(con_fd);
close(con_fd);
return 0;
}