当前位置: 首页 > 编程日记 > 正文

Linux C++/Java/Web/OC Socket网络编程

一,Linux C++ Socket网络编程

1.什么是TCP/IPUDP

  TCP/IPTransmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网(WANs)设计的。
  UDPUser Data Protocol,用户数据报协议)是与TCP相对应的协议。它是属于TCP/IP协议族中的一种。
  下面的图表明了这些协议的关系。

2.Socket在哪里呢?

3.Socket是什么呢?

  Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

  门面模式,用自己的话说,就是系统对外界提供单一的接口,外部不需要了解内部的实现。

4.有很多的框架,为什么还在从Socket开始?

  现在的跨平台网络编程框架很多,如Java的SSH,C/C++的Boost等。

  现在的分布式框架很多,如Hadoop等。

  Socket是分布式、云计算、网络编程的基础,对Socket的学习有利于对其他框架的理解。

  下图是Socket编程的基本流程:

第一步:建立一个socket

int socket(int af, int type, int protocol)

A. 'int af'代表地址族或者称为socket所代表的域,通常有两个选项: 
    1. AF_UNIX - 只在单机上使用。 
    2. AF_INET - 可以在单机或其他使用DARPA协议(UDP/TCP/IP)的异种机通信。 
B. 'int type'代表你所使用的连接类型,通常也有两种情况: 
    1. SOCK_STREAM - 用来建立面向连接的sockets,可以进行可靠无误的的数据传输 
    2. SOCK_DGRAM - 用来建立没有连接的sockets,不能保证数据传输的可靠性。
C. 'int protocol'通常设定为0。使系统选择默认的由协议族和连接类型所确定的协议。
D. 返回值是一个文件描述句柄,如果在此期间发生错误则返回-1并且设定了相应的errno。

int sockfd;if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {perror("socket 创建出错!");exit(1);}

第二步:绑定名字socket: bind() 

int bind(int sockfd, struct sockaddr *name, int namelen)

A. sockfd是从socket()调用得到的文件描述句柄。

B. name是一个指向sockaddr类型结构的一个指针。

C. namelen给出了文件名的具体长度。

在使用AF_INET地址族的时候,类型定义如下:

struct sockaddr_in {short int sin_family;unsigned short int sin_port;struct in_addr sin_addr;unsigned char sin_zero[8];
};

在这个结构种,name.sin_family应当被设定为AF_INET

struct sockaddr_in name;int sockfd;if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {exit(1);}name.sin_family = AF_INET;name.sin_port = htons(8087);name.sin_addr.s_addr = htonl(INADDR_ANY);bzero(&(name.sin_zero), 8); /* zero out the rest of the space */if (bind(sockfd, (struct sockaddr *) &name, sizeof(struct sockaddr))== -1) {exit(1);}

现在,如果没有问题的话,我们建立的socket就有一个名字了!相反,如果不成功,它会设定相应的错误代码,并使程序退出。

第三步:远程连接: connect() 

int connect(int sockfd, struct sockaddr *serv_addr, int addrlen)

A. sockfd是我们建立的文件描述句柄

B. serv_addr是一个sockaddr结构,包含目的的地址和端口号

C. addrlen 被设定为sockaddr结构的大小。

if (connect(sockfd, (struct sockaddr *) &name, sizeof(name)) < 0) {  exit(1); }

第四步:监听: listen() 

int listen(int sockfd, int backlog)

B. 参数backlog是指一次可以监听多少个连接

if (listen(sockfd, 20) == -1) { exit(1); }

第五步:阻塞接受连接: accept()

当有人试图从我们打开的端口登陆进来时,我们应该响应他,这个时候就要用到accept()函数了。

int accept(int sockfd, void *addr, int *addrlen)

conn = accept(sockfd, (struct sockaddr*) &name, sizeof(name));if (conn < 0) {exit(1);}

第六步:输入和输入的完成: send() and recv() 

int send(int sockfd, const void *msg, int len, int flags)
int recv(int sockfd, void *buf, int len, unsigned int flags)

send(): 
sockfd - socket file descriptor 
msg - message to send 
len - size of message to send 
flags - read 'man send' for more info, set it to 0 for now 

recv(): 
sockfd - socket file descriptor 
buf - data to receive 
len - size of buf 
flags - same as flags in send()

注意:如果使用的连接类型是SOCK_DGRAM,那么应该使用sendto()和recvfrom()来实现数据传输。

char buffer[BUFFER_SIZE];
while (1) {memset(buffer, 0, sizeof(buffer));int len = recv(conn, buffer, sizeof(buffer), 0);if (strcmp(buffer, "exit\n") == 0)break;fputs(buffer, stdout);send(conn, buffer, len, 0);}

结束: close() and shutdown() 

当传输结束时,应当关闭连接。

一个服务端等待, 客户端上传文件到服务端,通过输入要上传的文件名,目前只做到仅对当前执行文件的目录下的文件,应该在服务端收到文件路径之后进行处理的。

服务端代码:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netdb.h>
#include <arpa/inet.h>//for inet_ntoa
#include <unistd.h>//for fork()#define SERVER_PORT 6666
#define LISTEN_QUEUE  20
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512int main() {//设置一个socket地址结构server_addr,代表服务器internet地址, 端口struct sockaddr_in server_addr;bzero(&server_addr, sizeof(server_addr)); //把一段内存区的内容全部设置为0server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr = htons(INADDR_ANY);server_addr.sin_port = htons(SERVER_PORT);//创建用于internet的流协议(TCP)socket,用server_socket代表服务器socketint server_socket = socket(PF_INET, SOCK_STREAM, 0);if (server_socket < 0) {printf("Create Socket Failed!");exit(1);}//把socket和socket地址结构联系起来if (bind(server_socket, (struct sockaddr*) &server_addr,sizeof(server_addr))) {printf("Server Bind Port: %d Failed!\n", SERVER_PORT);exit(1);}//server_socket用于监听if (listen(server_socket, LISTEN_QUEUE)) {printf("Server Listen Failed!");exit(1);}while (1) {//定义客户端的socket地址结构client_addrchar buffer[BUFFER_SIZE];struct sockaddr_in client_addr;socklen_t length = sizeof(client_addr);int client_socket = accept(server_socket,(struct sockaddr*) &client_addr, &length);if (client_socket < 0) {printf("Server Accept Failed!\n");break;}bzero(buffer, BUFFER_SIZE);// 获取客户端要传输的文件名length = recv(client_socket, buffer, BUFFER_SIZE, 0);if (length < 0) {printf("Server Recieve Data Failed!\n");break;}char file_name[FILE_NAME_MAX_SIZE + 1];bzero(file_name, FILE_NAME_MAX_SIZE + 1);strncpy(file_name, buffer,strlen(buffer) > FILE_NAME_MAX_SIZE ?FILE_NAME_MAX_SIZE : strlen(buffer));// 新建文件FILE * fp = fopen(file_name, "w");if (NULL == fp) {printf("File: %s CAN NOT WRITE!\n", file_name);} else {bzero(buffer, BUFFER_SIZE);int file_block_length = 0;while ((file_block_length = recv(client_socket, buffer, BUFFER_SIZE,0)) > 0) {if (file_block_length < 0) {printf("Recieve Data From Client Failed!\n");break;}int write_length = fwrite(buffer, sizeof(char),file_block_length, fp);if (write_length < file_block_length) {printf("File: %s Write Failed\n", file_name);break;}bzero(buffer, BUFFER_SIZE);}fclose(fp);printf("File: %s Transfer Finished\n\n", file_name);}close(client_socket);}close(server_socket);return 0;
}
View Code

客户端

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netdb.h>
#include <arpa/inet.h>//for inet_ntoa
#include <unistd.h>//for fork()#define SERVER_PORT 6666
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512int main() {//设置一个socket地址结构client_addr,代表客户机internet地址, 端口struct sockaddr_in client_addr;bzero(&client_addr, sizeof(client_addr)); //把一段内存区的内容全部设置为0client_addr.sin_family = AF_INET; //internet协议族client_addr.sin_addr.s_addr = htons(INADDR_ANY); //INADDR_ANY表示自动获取本机地址client_addr.sin_port = htons(0); //0表示让系统自动分配一个空闲端口//创建用于internet的流协议(TCP)socket,用client_socket代表客户机socketint client_socket = socket(AF_INET, SOCK_STREAM, 0);if (client_socket < 0) {printf("Create Socket Failed!\n");exit(1);}//把客户机的socket和客户机的socket地址结构联系起来if (bind(client_socket, (struct sockaddr*) &client_addr,sizeof(client_addr))) {printf("Client Bind Port Failed!\n");exit(1);}//设置一个socket地址结构server_addr,代表服务器的internet地址, 端口struct sockaddr_in server_addr;bzero(&server_addr, sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(SERVER_PORT);socklen_t server_addr_length = sizeof(server_addr);// 向服务器发起连接,连接成功后client_socket代表了客户机和服务器的一个socket连接if (connect(client_socket, (struct sockaddr*) &server_addr,server_addr_length) < 0) {exit(1);}// 连接上服务器, 选择要上传的文件char file_name[FILE_NAME_MAX_SIZE + 1];bzero(file_name, FILE_NAME_MAX_SIZE + 1);printf("Please Input File Name Upload To Server: ");scanf("%s", file_name);char buffer[BUFFER_SIZE];bzero(buffer, BUFFER_SIZE);strncpy(buffer, file_name,strlen(file_name) > BUFFER_SIZE ? BUFFER_SIZE : strlen(file_name));FILE * fp = fopen(file_name, "r");if (NULL == fp) {printf("File: %s NOT FOUND! \n", file_name);exit(1);}// 发送文件名int nameLength = send(client_socket, buffer, BUFFER_SIZE, 0);if (nameLength < 0) {printf("File name Error! \n");exit(0);}bzero(buffer, BUFFER_SIZE);int file_block_length = 0;while ((file_block_length = fread(buffer, sizeof(char), BUFFER_SIZE, fp))> 0) {if (send(client_socket, buffer, file_block_length, 0) < 0) {printf("Send File:\t%s Failed\n", file_name);break;}bzero(buffer, BUFFER_SIZE);}printf("File:\t%s Transfer Finished\n", file_name);fclose(fp);close(client_socket);return 0;
}
View Code

计算机网络实验:Linux Apache下模拟服务器解析验证HTTP-Get请求并发回网页数据

HTTP请求格式:
<request-line>
<headers>
<blank line>
[<request-body>]
说明:第一行必须是一个请求行(request-line),用来说明请求类型,要访问的资源以及所使用的HTTP版本.
      紧接着是一个首部(header)小节,用来说明服务器要使用的附加信息.
      之后是一个空行.
      再后面可以添加任意的其他数据[称之为主体(body)].
例1 GET请求:

GET / HTTP/1.1
Accept: */*
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)
Host: www.google.cn
Connection: Keep-Alive
说明:请求的第一部分说明了该请求是一个GET请求.该行的第二部分是一个斜杠(/),用来说明请求的是该域名的根目录.该行的最后一部分说明使用的是HTTP1.1版本(另一个可选荐是1.0).
      第2行是请求的第一个首部,HOST将指出请求的目的地.User-Agent,服务器端和客户端脚本都能访问它,它是浏览器类型检测逻辑的重要基础.该信息由你的浏览器来定义,并且在每个请求中自动发送.Connection,通常将浏览器操作设置为Keep-Alive
      第三部分,空行,即使不存在请求主体,这个空行也是必需的.

例2 POST请求:

POST / HTTP1.1
Host:www.wrox.com
User-Agent:Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)
Content-Type:application/x-www-form-urlencoded
Content-Length:40
Connection: Keep-Alive

name=Professional%20Ajax&publisher=Wiley
说明:请求行开始处的GET改为POST,以表示不同的请求类型.
      Content-Type说明了请求主体的内容是如何编码的.浏览器始终以application/x-www-form-urlencoded的格式编码来传送数据,这是针对简单URL编码的MIME类型.Content-Length说明了请求主体的字节数.
      最后请求主体.名称-值对的形式.

HTTP响应格式:
<status-line>

<headers>
<blank line>
[<response-body>]

HTTP/1.1 200 OK
Date: Fri, 22 May 2009 06:07:21 GMT
Content-Type: text/html; charset=UTF-8

<html>
      <head></head>
      <body>
            <!--body goes here-->
      </body>
</html>
说明:HTTP状态码200,找到资源,并且一切正常.
      Date:生成响应的日期和时间.
      Content-Type:指定了MIME类型的HTML(text/html),编码类型是UTF-8
      HTML源文体.

 

 

程序代码与简要分析

数据包分析:得到请求的文件,用户名与密码
int analysis_packet(char *packet, char *file, char *ID, char *psw)
HTTP数据包头 202根据时间与数据包内容大小构建,404返回无法连接
int headerBuilder(char *msg, int status, int size)
与本机Java写成的运行的ServerSocket连接本机MySQL数据库校验用户名与密码
bool check(char *ID, char *psw)
主函数,作为服务端监听本机3334端口的数据请求,根据数据包请求校验与分析。

ServerSocket在本机8081端口监听,为Java与MySQL交互的服务端,对每个Socket请求开辟一个线程处理,返回校验结果。
#include <cstdio>
#include <stdlib.h>
#include <errno.h>
#include <cstring>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <time.h>
#include <arpa/inet.h>//for inet_ntoa
#include <unistd.h>//for fork()#define MAXN 20480struct INFO {char ID[50], psw[50];
};int analysis_packet(char *packet, char *file, char *ID, char *psw) {char *p, *q;if ((p = strtok(packet, " \r")) == NULL)return 0;if (strcmp(p, "GET") == 0) { //GETif ((p = strtok(NULL, " \r")) == NULL)return 1;q = p;if ((p = strtok(NULL, " \r")) != NULL && strcmp(p, "HTTP/1.1") == 0) { //协议HTTP/1.1if ((q = strtok(q, "?")) != NULL) {strcpy(file, q); //文件名if ((q = strtok(NULL, "?")) != NULL) {char *tmp;if ((tmp = strtok(q, "&")) != NULL) {strcpy(ID, tmp + 3);}if ((tmp = strtok(NULL, "&")) != NULL) {strcpy(psw, tmp + 3);}return 2;}}return 1;} elseprintf("未知的协议!\n");} elseprintf("未知的请求!\n");return 0;
}
int headerBuilder(char *msg, int status, int size) {char num[5];char *wday[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };char *wmon[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug","Sep", "Oct", "Nov", "Dec" };struct tm *ptr;time_t it;time(&it);ptr = localtime(&it); //取得本地时间switch (status) {case 200://状态行strcat(msg, "HTTP/1.1 200 OK\r\n");//首部strcat(msg, "Date: ");strcat(msg, wday[ptr->tm_wday]);strcat(msg, ", ");sprintf(num, "%d", ptr->tm_mday);strcat(msg, num);strcat(msg, " ");strcat(msg, wmon[ptr->tm_mon]);strcat(msg, " ");sprintf(num, "%d", 1900 + ptr->tm_year);strcat(msg, num);strcat(msg, " ");sprintf(num, "%d", ptr->tm_hour);strcat(msg, num);strcat(msg, ":");sprintf(num, "%d", ptr->tm_min);strcat(msg, num);strcat(msg, ":");sprintf(num, "%d", ptr->tm_sec);strcat(msg, num);strcat(msg, " GMT\r\n");strcat(msg, "Content-Type: text/html;charset=utf-8\r\n");strcat(msg, "Content-Length: ");sprintf(num, "%d", size);strcat(msg, num);strcat(msg, "\r\n\r\n");break;case 404://状态行strcat(msg, "HTTP/1.1 404 Not Found\r\n");//首部strcat(msg, "Date: ");strcat(msg, wday[ptr->tm_wday]);strcat(msg, ", ");sprintf(num, "%d", ptr->tm_mday);strcat(msg, num);strcat(msg, " ");strcat(msg, wmon[ptr->tm_mon]);strcat(msg, " ");sprintf(num, "%d", 1900 + ptr->tm_year);strcat(msg, num);strcat(msg, " ");sprintf(num, "%d", ptr->tm_hour);strcat(msg, num);strcat(msg, ":");sprintf(num, "%d", ptr->tm_min);strcat(msg, num);strcat(msg, ":");sprintf(num, "%d", ptr->tm_sec);strcat(msg, num);strcat(msg, " GMT\r\n\r\n");break;}return 0;
}
bool check(char *ID, char *psw) {printf("check info %s %s\n", ID, psw);int cfd = socket(AF_INET, SOCK_STREAM, 0);int recbytes;char buffer[50] = { '\0' };struct sockaddr_in s_add;if (-1 == cfd) {printf("socket fail ! \r\n");return 0;}bzero(&s_add, sizeof(struct sockaddr_in));s_add.sin_family = AF_INET;s_add.sin_addr.s_addr = inet_addr("127.0.0.1");s_add.sin_port = htons(8083);if (connect(cfd, (struct sockaddr *) (&s_add), sizeof(s_add)) == -1) {printf("connect fail !\r\n");return 0;}printf("connect ok !\r\n");strcpy(buffer, "login");printf("sending %s\n", buffer);if ((recbytes = send(cfd, buffer, 5, 0)) == -1) {return 0;}strcpy(buffer, ID);buffer[strlen(ID)] = '\0';printf("sending %s\n", buffer);if ((recbytes = send(cfd, buffer, strlen(ID), 0)) == -1) {return 0;}strcpy(buffer, psw);buffer[strlen(psw)] = '\0';printf("sending %s\n", buffer);if ((recbytes = send(cfd, buffer, strlen(psw), 0)) == -1) {return 0;}if (-1 == (recbytes = recv(cfd, buffer, 3, 0))) {return 0;}close(cfd);printf("receive %s\n", buffer);if (strcmp(buffer, "YES"))return 1;return 0;
}int main() {int sockfd, client_fd;struct sockaddr_in my_addr;struct sockaddr_in remote_addr;char msg[MAXN] = { '\0' };//创建套接字if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {perror("socket create failed!");exit(1);}my_addr.sin_family = AF_INET; //通信类型my_addr.sin_port = htons(3334); //端口my_addr.sin_addr.s_addr = INADDR_ANY; //本地地址bzero(&(my_addr.sin_zero), 8);//绑定端口地址if (bind(sockfd, (struct sockaddr*) &my_addr, sizeof(struct sockaddr))== -1) {exit(1);}//开始监听if (listen(sockfd, 10) == -1) {exit(1);}while (1) {socklen_t sin_size = sizeof(struct sockaddr_in);if ((client_fd = accept(sockfd, (struct sockaddr*) &remote_addr,&sin_size)) == -1) {break;}printf("收到%s的报文\n", (char*) inet_ntoa(remote_addr.sin_addr));//子进程段if (!fork()) {char buf[MAXN];char file[50] = { '\0' };char path[100] = "/Users/pcforsong/ksacm"; //服务器文件的路径//读报文if (read(client_fd, buf, MAXN) < 0) {perror("reading stream error!");continue;}// printf("%s\n", buf);
FILE *fp;char ID[50] = { '\0' }, psw[50] = { '\0' };bool checked = false;int OP = analysis_packet(buf, file, ID, psw);if (OP) { //get//生成本地文件路径
                strcat(path, file);printf("path: %s\n", path);printf("info: %s %s\n", ID, psw);if (!checked && OP == 2 && !check(ID, psw))exit(0);checked = 1;if ((fp = fopen(path, "r")) != NULL) { //找到文件//通过文件指针计算文件大小fseek(fp, 0, SEEK_END); //到文件结尾int size = ftell(fp); //与文件首偏移字节数fseek(fp, 0, SEEK_SET); //移回开头//填写msg添加200响应报文头headerBuilder(msg, 200, size);while (fgets(buf, 2048, fp) != NULL) {strcat(msg, buf);};fclose(fp);} else {//为msg添加404响应报文头headerBuilder(msg, 404, 0);}//向client发送应答报文msg// printf("%s\n", msg);if (send(client_fd, msg, strlen(msg), 0) == -1)perror("send error!");close(client_fd);} elseprintf("报文解析失败!\n");exit(0);}close(client_fd);}return 0;
}

附上Windows Socket编程 http://www.cppblog.com/bujiwu/archive/2009/01/11/71707.aspx

二,JAVA ServerSocket

声明一个ServerSocket打开一个未占用的套接口,并开始ServerSocket.aceept 监听端口。

其他程序可以Socket连接IP与端口,new BufferReader(new InputStreamReader(socket.getInputStream()))接收消息。

这里使用多线程处理Socket请求,利用继承自Thread类的自定义线程类重载它的run()方法,这样虽然每个Socket都被同样的代码处理,但彼此相互独立,各自拥有各自的资源互不干扰。

实现多线程有两个办法,一种采用线程类继承Thread来实现。

另一种做法是实现Runnable接口,通过 new Thread(Runnable的子类实例) 来实现多线程。要提一句,Runnable接口可以实现对同一实例的多线程处理,即线程资源共享,是继承Thread不能做到的,所以Runnable接口被广泛使用于多线程程序。 Thread类构造函数可以为Runnable target赋值,并且Thread类的run方法就是调用target.run(),所以用Runnable接口定义的run方法是父类的。

new Thread(new Runnable(){public void run(){} // 重载Thread中Runnable target的run方法
}) {public void run(){} //子类重载继承自父类的run方法
}

TCP协议

import java.io.*;
import java.net.*;
import java.sql.*;
import java.util.Vector;class ServerThread implements Runnable {private Socket socket;// 定义套接口private BufferedReader in;// 定义输入流private PrintWriter out;// 定义输出流
    Connection conn;int no;public ServerThread(Socket s) throws IOException {// 线程构造函数socket = s;// 取得传递参数in = new BufferedReader(new InputStreamReader(socket.getInputStream()));// 创建输入流out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);// 创建输出流
    }public void run() {// 重写run方法System.out.println("监听Socket中...");try {Class.forName("com.mysql.jdbc.Driver");// 连接数据库conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/javaicq", "root", "");while (true) {String OP = in.readLine();// 停止if (OP.equals("end"))break;// 登录else if (OP.equals("login")) {try {PreparedStatement prepare = conn.prepareStatement("select nickname,password from icq where icqno=?");// 设定数据库查寻条件int g = Integer.parseInt(in.readLine());String passwd = in.readLine().trim();prepare.setInt(1, g);// 设定参数ResultSet rs = prepare.executeQuery();// 执行数据库查寻if (!rs.next())out.println("用户不存在");else {// 以下比较输入的号码于密码是否相同String pass = rs.getString("password").trim();if (!passwd.equals(pass)) {out.println("密码错误");} else {// 以及注册用户的ip 地址PreparedStatement online = conn.prepareStatement("update icq set ip=? where icqno=?");online.setString(1, socket.getInetAddress().getHostAddress());online.setInt(2, g);online.executeUpdate();// set status onlinePreparedStatement status = conn.prepareStatement("update icq set status=1 where icqno=?");status.setInt(1, g);status.executeUpdate();out.println("YES");}}rs.close();} catch (Exception e) {e.printStackTrace();out.println("Error");}}// 新建else if (OP.equals("new")) {try {// 准备接受用户的呢称,密码,email,个人资料,籍贯,头像等信息String nickname = in.readLine().trim();String password = in.readLine().trim();String email = in.readLine().trim();String info = in.readLine().trim();String place = in.readLine().trim();int picindex = Integer.parseInt(in.readLine());PreparedStatement userInfo = conn.prepareStatement("insert into icq(nickname,password,email,info,place,pic,icqno) values(?,?,?,?,?,?,?)");userInfo.setString(1, nickname);userInfo.setString(2, password);userInfo.setString(3, email);userInfo.setString(4, info);userInfo.setString(5, place);userInfo.setInt(6, picindex);userInfo.setInt(7, Integer.parseInt(Double.toString(Math.random()).substring(3, 8)));userInfo.executeUpdate();// 执行数据库添加// 查询其注册的号码PreparedStatement qNo = conn.prepareStatement("select icqno from icq where nickname=?");qNo.setString(1, nickname);ResultSet rs = qNo.executeQuery();while (rs.next()) { // 找到最近注册的号码no = rs.getInt(1);}out.println("YES");out.println(no);rs.close();} catch (Exception e) {e.printStackTrace();out.println("Error");}}}} catch (IOException e) {e.printStackTrace();} catch (SQLException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();} finally {try {conn.close();socket.close();} catch (IOException e) {} catch (SQLException e) {}}}
}public class Server {// 主服务器类public static void main(String args[]) throws IOException {ServerSocket so = new ServerSocket(8081);// 在8081端口创建套接口so.setSoTimeout(100000);System.out.println("服务器已启动 " + so);Socket testServer = new Socket(InetAddress.getLocalHost(), 8081);PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(testServer.getOutputStream())), true);try {while (true) {Socket socket = so.accept();// 无限监听客户的请求System.out.println("建立Socket连接:" + socket);try {
//                    out.println("login");
//                    out.println(123);
//                    out.println(123);ServerThread st = new ServerThread(socket);// 创建新线程处理Socketnew Thread(st).start(); } catch (IOException e) {socket.close();}}} catch (SocketTimeoutException e) {System.out.println("超时断开连接");} finally {so.close();}}
}
View Code

UDP协议

// 创建UDP Socket
try {DatagramSocket sendSocket = new DatagramSocket();DatagramSocket receiveSocket = new DatagramSocket(udpPORT);System.out.println("创建UDP数据报成功");} catch (SocketException se) {se.printStackTrace();System.out.println("创建UDP数据报失败");}
// 接收数据报byte array[] = new byte[512];for (int x = 0; x < 512; x++)array[x] = ' ';DatagramPacket  receivePacket = new DatagramPacket(array, array.length);receiveSocket.receive(receivePacket);byte[] data = receivePacket.getData();String infofromip = receivePacket.getAddress().getHostAddress().toString().trim();received = new String(data, 0, data.length);
// 发送数据报
String info = "offline";byte[] data = info.getBytes();sendPacket = new DatagramPacket(data, s.length(),InetAddress.getByName(whoaddmesip.get(i).toString()),sendPort);sendSocket.send(sendPacket);

二,OpenSSL编程

http://www.cnblogs.com/LittleHann/p/3741907.html

三,WebSocket

WebSocket是为解决客户端与服务端实时通信而产生的技术。其本质是先通过HTTP/HTTPS协议进行握手后创建一个用于交换数据的TCP连接,此后服务端与客户端通过此TCP连接进行实时通信。

WebSocket规范当前还没有正式版本,草案变化也较为迅速。Tomcat7(本文中的例程来自7.0.42)当前支持RFC 6455定义的WebSocket,而RFC 6455目前还未冻结,将来可能会修复一些Bug,甚至协议本身也可能会产生一些变化。

RFC6455定义的WebSocket协议由握手和数据传输两个部分组成。

来自客户端的握手信息类似如下:

  1. GET /chat HTTP/1.1
  2. Host: server.example.com
  3. Upgrade: websocket
  4. Connection: Upgrade
  5. Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
  6. Origin: http://example.com
  7. Sec-WebSocket-Protocol: chat, superchat
  8. Sec-WebSocket-Version: 13


服务端的握手信息类似如下:

  1. HTTP/1.1 101 Switching Protocols
  2. Upgrade: websocket
  3. Connection: Upgrade
  4. Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
  5. Sec-WebSocket-Protocol: chat


一旦客户端和服务端都发送了握手信息并且成功握手,则数据传输部分将开始。数据传输对客户端和服务端而言都是一个双工通信通道,客户端和服务端来回传递的数据称之为“消息”。

客户端通过WebSocket URI发起WebSocket连接,WebSocket URIs模式定义如下:

ws-URI = "ws:" "//" host [ ":" port ] path [ "?" query ]

wss-URI = "wss:" "//" host [ ":" port ] path [ "?" query ]

  ws是普通的WebSocket通信协议,而wss是安全的WebSocket通信协议(就像HTTP与HTTPS之间的差异一样)。在缺省情况下,ws的端口是80而wss的端口是443。

关于WebSocke协议规范的完整详尽说明,请参考RFC 6455。

  Tomcat7提供的与WebSocket相关的类均位于包org.apache.catalina.websocket之中(包org.apache.catalina.websocket的实现包含于文件catalina.jar之中),它包含有类Constants、MessageInbound、StreamInbound、WebSocketServlet、WsFrame、WsHttpServletRequestWrapper、WsInputStream、WsOutbound。这些类的关系如图 1所示。

图1

包org.apache.catalina.websocket中的这些类为WebSocket开发服务端提供了支持,这些类的主要功能简述如下:

        Constants:包org.apache.catalina.websocket中用到的常数定义在这个类中,它只包含静态常数定义,无任何逻辑实现。

        MessageInbound:基于消息的WebSocket实现类(带内消息),应用程序应当扩展这个类并实现其抽象方法onBinaryMessage和onTextMessage。

       StreamInbound:基于流的WebSocket实现类(带内流),应用程序应当扩展这个类并实现其抽象方法onBinaryData和onTextData。

       WebSocketServlet:提供遵循RFC6455的WebSocket连接的Servlet基本实现。客户端使用WebSocket连接服务端时,需要将WebSocketServlet的子类作为连接入口。同时,该子类应当实现WebSocketServlet的抽象方法createWebSocketInbound,以便创建一个inbound实例(MessageInbound或StreamInbound)。

       WsFrame:代表完整的WebSocket框架。

       WsHttpServletRequestWrapper:包装过的HttpServletRequest对象。

       WsInputStream:基于WebSocket框架底层的socket的输入流。

       WsOutbound:提供发送消息到客户端的功能。它提供的所有向客户端的写方法都是同步的,可以防止多线程同时向客户端写入数据。

Tomcat是怎样实现WebSocket的
1)要开始使用WebSocket,你必须继承Tomcat的WebSocket类
2)编写自己的类,它继承WebSocketServlet类(由于这是一个Servlet,因此必须把它映射到URL)
3)实现一个消息监听器类,由于它继承自WebSocketServlet类,因此需要自己实现createWebSocketInbound()方法

此方法能够用于监听事件。有两个必须有的方法:
一是 protected void onBinaryData(InputStream inStream);
二是protected void onTextData(Reader reader);

当WebSocket打开或关闭时,如果你希望收到通知,只需简单地重写onOpen()方法和onClose()方法。

把数据写到客户端,必须有StreamInbound实现类,它会引用发送器组件WsOutbound,可以简单地通过调用来取到它:myStreamInbound.getWsOutbound()

还可以发送二进制数据writeBinaryData(int b);  

或者发送文本数据到客户端writeTextData(char c);  

注意:这些方法是互斥的。不要同时调用两种方法,以期待既发送二进制数据,又发送文本数据。

package com.ibcio;import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;import org.apache.catalina.websocket.StreamInbound;@WebServlet(urlPatterns = { "/message" })
// 如果要接收浏览器的ws://协议的请求就必须实现WebSocketServlet这个类
public class WebSocketMessageServlet extendsorg.apache.catalina.websocket.WebSocketServlet {private static final long serialVersionUID = 1L;public static int ONLINE_USER_COUNT = 1;public String getUser(HttpServletRequest request) {return (String) request.getSession().getAttribute("user");}// 跟平常Servlet不同的是,需要实现createWebSocketInbound,在这里初始化自定义的WebSocket连接对象
    @Overrideprotected StreamInbound createWebSocketInbound(String subProtocol,HttpServletRequest request) {return new WebSocketMessageInbound(this.getUser(request));}
}

JS

var websocket;//初始话WebSocketfunction initWebSocket() {if (window.WebSocket) {websocket = new WebSocket(encodeURI('ws://localhost:8080/WebSocket/message'));websocket.onopen = function() {//连接成功win.setTitle(title + '&nbsp;&nbsp;(已连接)');}websocket.onerror = function() {//连接失败win.setTitle(title + '&nbsp;&nbsp;(连接发生错误)');}websocket.onclose = function() {//连接断开win.setTitle(title + '&nbsp;&nbsp;(已经断开连接)');}//消息接收websocket.onmessage = function(message) {var message = JSON.parse(message.data);//接收用户发送的消息if (message.type == 'message') {output.receive(message);} else if (message.type == 'get_online_user') {//获取在线用户列表var root = onlineUser.getRootNode();} else if (message.type == 'user_join') {//用户上线var root = onlineUser.getRootNode();var user = message.user;var node = root.createNode({id : user,text : user,iconCls : 'user',leaf : true});root.appendChild(node);} else if (message.type == 'user_leave') {//用户下线var root = onlineUser.getRootNode();var user = message.user;var node = root.findChild('id',user);root.removeChild(node);}}}};//发送消息function send() {var message = {};if (websocket != null) {if (input.getValue()) {Ext.apply(message, {from : user,content : input.getValue(),timestamp : new Date().getTime(),type : 'message'});websocket.send(JSON.stringify(message));//output.receive(message);input.setValue('');}} else {Ext.Msg.alert('提示', '您已经掉线,无法发送消息!');}}});
View Code

四、Objective-C Socket编程

iPhone的标准推荐CFNetwork C库编程.但是编程比较烦躁。在其它OS往往用类来封装的对Socket函数的处理。比如MFC的CAsysncSocket.在iphone也有类似于开源项目.cocoa AsyncSocket库, 官方网站:http://code.google.com/p/cocoaasyncsocket/ 它用来简化CFnetwork的调用.

//建立基于UDP的Socket连接
-(void)openUDPServer{//初始化udpAsyncUdpSocket *tempSocket=[[AsyncUdpSocket alloc] initWithDelegate:self];self.udpSocket=tempSocket;[tempSocket release];//绑定端口NSError *error = nil;[self.udpSocket bindToPort:4333 error:&error];//发送广播设置[self.udpSocket enableBroadcast:YES error:&error];//加入群里,能接收到群里其他客户端的消息[self.udpSocket joinMulticastGroup:@"127.0.0.1" error:&error];//启动接收线程[self.udpSocket receiveWithTimeout:-1 tag:0];
}//通过UDP,发送消息
-(void)sendMassage:(NSString *)message
{   NSDate *nowTime = [NSDate date];NSMutableString *sendString=[NSMutableString stringWithCapacity:100];[sendString appendString:message];//开始发送BOOL res = [self.udpSocket sendData:[sendString dataUsingEncoding:NSUTF8StringEncoding] toHost:@"127.0.0.1"port:4333 withTimeout:-1 tag:0];if (!res) {UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示"message:@"发送失败"delegate:selfcancelButtonTitle:@"取消"otherButtonTitles:nil];[alert show];[alert release];}
}

其委托方法

#pragma mark UDP Delegate Methods
- (BOOL)onUdpSocket:(AsyncUdpSocket *)sock didReceiveData:(NSData *)data withTag:(long)tag fromHost:(NSString *)host port:(UInt16)port
{   [self.udpSocket receiveWithTimeout:-1 tag:0];NSLog(@"host---->%@",host);//接收到数据回调

NSString *info=[[[NSString alloc] initWithData:data encoding: NSUTF8StringEncoding] autorelease];

    return YES;
}- (void)onUdpSocket:(AsyncUdpSocket *)sock didNotSendDataWithTag:(long)tag dueToError:(NSError *)error
{//无法发送时,返回的异常提示信息
}
- (void)onUdpSocket:(AsyncUdpSocket *)sock didNotReceiveDataWithTag:(long)tag dueToError:(NSError *)error
{   //无法接收时,返回异常提示信息
}

转载于:https://www.cnblogs.com/updateofsimon/p/3567022.html

相关文章:

ASP.NET抓取其他网页代码

在.Net 平台下&#xff0c;创建一个ASP.Net的程序 1、引用两个NAMESPACE using System.Text //因为用了Encoding类 using System.Net //因为用了WebClient 类 2、整个程序用了三个控件 txtUrl //输入你要获取的网页地址 TEXTBOX控件 txtBody //得到你要获取的网…

特斯拉遇上 CPU:程序员的心思你别猜

作者 | 码农的荒岛求生来源 | 码农的荒岛求生图源 | 视觉中国18世纪流水线的诞生带来了制造技术的变革&#xff0c;人类当今拥有琳琅满目物美价廉的商品和流水线技术的发明密不可分&#xff0c;因此当你喝着可乐、吹着空调、坐在特斯拉里拿着智能手机刷这篇文章时需要感谢流水线…

《算法技术手册》一2.4.6 二次方的算法性能

2.4.6 二次方的算法性能 现在考虑一个类似的问题&#xff1a;两个n位的整数相乘。例2-4展示了使用小学课堂上学过的算法实现的乘法运算&#xff0c;其中n位数字的表示方法与之前的加法一样。 例2-4&#xff1a;mult乘法的Java实现 public static void mult (int[] n1, int[] n2…

如何使用 OpenCV 实现图像均衡?

来源 | 小白视觉志头图 | 下载于视觉中国我们已经练习了很多图像处理——操作图像&#xff08;精确地说是图像矩阵&#xff09;。为此&#xff0c;我们探索了图像的均衡方法&#xff0c;以便在一定程度上增强对比度&#xff0c;以使被处理的图像看起来比原始图像更好&#xff0…

《中国人工智能学会通讯》——1.42 理解情感

1.42 理解情感 安德鲁摩尔认为&#xff0c;人工智能能“感受”人类情感是人工智能研究领域最重要、也最先进的一个方向。扬波利斯基认为&#xff0c;计算机能够理解语言的能力最终会向人和计算机“无缝沟通”的方向发展。 越来越精准的图像、声音和面部识别系统能让计算机更好探…

matlab中help所有函数功能的英文翻译

doc funname 在帮助浏览器中打开帮助文档help funname 在命令窗口打开帮助文档helpbrowser 直接打开帮助浏览器lookfor funname 搜索某个关键字相关函数demo 打开视频教程 转http://blog.renren.com/share/239121107/690877048 里面有些不全的&#xff0c;自己用到的已添加…

C# 静态构造函数

&#xff08;1&#xff09;用于对静态字段、只读字段等的初始化。 &#xff08;2&#xff09;添加static关键字&#xff0c;不能添加访问修饰符&#xff0c;因为静态构造函数都是私有的。 &#xff08;3&#xff09;类的静态构造函数在给定应用程序域中…

破解数据流通痛点,华控清交的隐私计算之道

从无序中寻找踪迹&#xff0c;从眼前事探索未来。 正值 IT 黄金十年新开端&#xff0c; CSDN 欲以中立技术社区专业、客观的角度&#xff0c;深度探讨中国前沿 IT 技术演进&#xff0c;现在推出年度重磅企划栏目——「拟合」&#xff0c;通过对话企业高管大咖&#xff0c;跟踪报…

mac系统添加VSCode到右键菜单(转)

转自&#xff1a;https://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/001470969077294a6455fc9cd1f48b69f82cd05e7fa9b40000 在Mac系统上&#xff0c;Finder选中一个目录&#xff0c;右键菜单并没有“通过Code打开”这个操作。不过我们可以…

在 C# 中通过 P/Invoke 调用Win32 DLL

&#xff0c;.NET Framework 1.0 或 1.1 版类库中存在任何 Windows 所没有的功能限制都不足为怪。毕竟&#xff0c;32 位的 Windows&#xff08;不管何种版本&#xff09;是一个成熟的操作系统&#xff0c;为广大客户服务了十多年。相比之下&#xff0c;.NET Framework 却是一个…

xp/2003开关3389指令

开启3389&#xff1a; echo offtitle 开启3389clsrem 开启3389reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 00000000 /f >nulecho.echo 提示你&#xff1a;3389已经开启 关闭3389&…

TIOBE 新榜单:Python 超越 Java 重回第二,Rust 崛起

作者 | 苏宓出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;TIOBE 官方最新发布了 5 月的编程语言榜单&#xff0c;不妨一起来看一下本月榜单中又有哪些最新的变化呢&#xff1f;Python 重回第二和 4 月相比&#xff0c;本月榜单的 TOP 10 中变化最大的非 Python 与…

Docker编排工具Fig介绍

本文讲的是Docker编排工具Fig介绍&#xff0c;【编者的话】Fig是一个基于Docker的用于快速搭建开发环境的工具&#xff0c;目前Fig团队已经加入Docker公司。Fig通过一个配置文件来管理多个Docker容器&#xff0c;非常适合组合使用多个容器进行开发的场景。Fig可以和Docker一起来…

java调用ffmpeg,mencoder进行视频转换,读取时长等

2019独角兽企业重金招聘Python工程师标准>>> 以前做的一个基于ffmpeg的视频格式转换的程序&#xff0c;现在抽空整理一下&#xff0c;很多地方都是从别的大神那借鉴的&#xff0c;只是把自己的觉得有用的&#xff0c;对别人有帮助的拿出来分享分享&#xff0c;下面是…

数字人民币实现可控匿名交易?产业升级离不开安全可信的“数字底座”

自央行进行数字人民币试点测试工作以来&#xff0c;人们讨论最多的可能是它的便捷性、匿名性。不过&#xff0c;它的意义远不止于人类个体层面。 作为一种面向未来的货币形式&#xff0c;在未来数字经济时代&#xff0c;央行数字人民币的普及无疑将加速全球资产数字化和身份数…

apache+tomcat 搭建负载均衡系统

apachetomcatmod_jk 搭建负载均衡系统。0.os系统采用centos6.8 x64 2.6.32-642.el6.x86_641.首先安装好jdk环境本次采用jdk-8u111-linux-x64.gz jdk和jre的安装目录要不同&#xff0c;否则的话lib目录下没有dt.jar 和tools.jar 要配置好环境变量如下 vi /etc/profile #ad…

从普本到北大:我的跨校跨专业考研经验

首先做一个我考研情况的简介。 经历了2013年考研的混战&#xff0c;据说是史上考研人数顶峰的年份&#xff0c;因为2014改革&#xff0c;不再有自费生之后&#xff0c;人民群众对于所谓学术硕士的需求量激减&#xff0c;继 而投奔价格费用相当&#xff0c;读书年份较少的专业硕…

C#中使用DirectX编程

我感觉声音的播放比较简单。我们从播放声音开始。为什么我这么觉得&#xff1f;我也不知道。这里是展示最最最最最简单的DirectX播放声音的例子&#xff0c;我尽量省略了无关的代码。最后的代码只有19行&#xff0c;够简单了吧&#xff1f; 准备工作&#xff1a;1.安装了Direc…

40+场面试,100%通过率,我想分享的14条经验

来源 | 陈同学在搬砖头图 | 下载于视觉中国大家好&#xff0c;我是陈同学&#xff0c;首先来一个简单的自我介绍和个人的经历分享。我的本科和硕士均就读于哈工大&#xff0c;在研究生期1年时间内自学操作系统、计算机网络、C、数据结构等&#xff0c;累计学习30本书、500博客文…

云端卫士架构师讲DDoS攻击的智能防御之道

DDoS即分布式拒绝服务攻击&#xff0c;这是一场关乎资源的较量&#xff0c;攻击者通过自己控制的大量僵尸主机&#xff0c;向目标设施&#xff08;服务器、运营商网络和基础架构等&#xff09;发起洪水猛兽般的流量型攻击&#xff0c;或是连绵不绝的应用型攻击。 如果将受害者比…

C#中方法参数的四种类型

C&#xff03;中方法的参数有四种类型&#xff1a;&#xff0d;值参数&#xff1a;不含任何修饰符。方法中的形参是实参的一份拷贝&#xff0c;形参的改变不会影响到内存中实参的的值&#xff0c;实参是安全的。&#xff0d;引用参数&#xff1a;以ref修饰符声明。传递的参数实…

赠书 | 算力时代,用 Python 来快速解决复杂问题

Python作为一种编程语言&#xff0c;拥有简洁、高效的表达能力。与此同时&#xff0c;Python语言环境中还配备各种软件库&#xff0c;即模块。结合实际问题&#xff0c;选择适当的模块&#xff0c;便可生成简单、快速、正确的程序。书中列举了一些数值计算的简单例题&#xff0…

用for实现Go的while和do...while

Go的while和do...while实现 Go语言没有while和do...while语法&#xff0c;我们可以通过for实现&#xff1a;即break在业务代码执行前相当与while&#xff0c;break在业务代码执行后相当do...while while for {if condition {break}xxxxxxxx } do...while for {xxxxxxxxif cond…

DTCC:数据库安全重点在数据拷贝过程中

本文讲的是DTCC&#xff1a;数据库安全重点在数据拷贝过程中&#xff0c;2017年5月11日-13日&#xff0c;2017中国数据库技术大会于北京国际会议中心盛大开幕。作为国内最受关注的数据库技术大会&#xff0c;本届大会以“数据驱动价值发现”为主题&#xff0c;汇集多个领域的百…

Log4J配置方式Java工程测试

2019独角兽企业重金招聘Python工程师标准>>> Log4J配置方式 1、 导入jar包 Commons-logging .jarLog4j-1.2.17.jar2、 编写log4j.properties 文件 ############## ############################## 优先级 INFO ,输出到console_log 和filelog 两个位置 log4j.root…

C#“装箱”(boxing)与“拆箱”(unboxing)

装箱和拆箱&#xff1a;任何值类型、引用类型可以和object&#xff08;对象&#xff09;类型之间进行转换。装箱转换是指将一个值类型隐式或显式地转换成一个object类型&#xff0c;或者把这个值类型转换成一个被该值类型应用的接口类型&#xff08;interface-type&#xff09;…

无人机、IoT 设备都有漏洞?专访以色列老牌安全企业Check Point | 拟合

从无序中寻找踪迹&#xff0c;从眼前事探索未来。2021 年正值黄金十年新开端&#xff0c;CSDN 以中立技术社区专业、客观的角度&#xff0c;深度探讨中国前沿 IT 技术演进&#xff0c;推出年度重磅企划栏目——「拟合」&#xff0c;通过对话企业技术高管大咖&#xff0c;跟踪报…

sql server 在占用服务器内存居高不下怎么办【转】

在管理一个测试服务器的时候&#xff0c;内存使用率居高不下&#xff0c;在资源管理器中查看到 sql server 2008 占用了80%的系统资源&#xff0c;于是找到了一下资料&#xff0c;并解决了Sql Server 2008 占用内存过大的问题。 转自百度经验http://jingyan.baidu.com/article…

C# checked、unchecked操作符

checked和unchecked操作符用于整型算术运算时控制当前环境中的溢出检查。下列运算参与了checked和unchecked检查&#xff08;操作数均为整数&#xff09;&#xff1a;1&#xff09; 预定义的&#xff0b;&#xff0b;和――一元运算符。2&#xff09; 预定义的&#xff0d;一…

TPAMI 2021 | 深度赋智AutoDL系列竞赛世界冠军方案首次公开

导读&#xff1a;「深度赋智」斩获NeurIPS-AutoDL 2019系列竞赛总决赛世界冠军&#xff0c;在图像/音频/视频/文本/表格不同场景的十个数据集上稳定获得八项第一和均分第一。为共同推动AutoDL技术的快速发展&#xff0c;冠军方案的技术细节首次公开&#xff0c;最新相关论文已被…